├── .gitignore ├── docs ├── requirements.txt ├── example-configuration.rst └── automatic-escaping.rst ├── images ├── smartparens-wrap.gif ├── smartparens-insert.gif ├── smartparens-slurp.gif └── smartparens-navigate.gif ├── smartparens-pkg.el ├── dev ├── README.md ├── skip-function.org ├── actions.org ├── _old │ ├── talk.org │ ├── smartparens.org │ ├── parser-system.org │ └── presentation2.org └── sp-defpair.org ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md └── workflows │ └── test.yml ├── .dir-locals.el ├── test ├── smartparens-lua-test.el ├── smartparens-get-paired-expression-c-test.el ├── smartparens-go-test.el ├── smarparents-clojure-test.el ├── smartparens-search-fn-test.el ├── smartparens-ocaml-test.el ├── smartparens-rst-test.el ├── smartparens-slurp-test.el ├── smartparens-get-suffix-test.el ├── smartparens-settings-sp-pair-test.el ├── smartparens-text-test.el ├── smartparens-haskell-test.el ├── smartparens-javascript-test.el ├── smartparens-get-stringlike-expression-python-test.el ├── smartparens-advice-test.el ├── smartparens-scala-test.el ├── smartparens-evil-test.el ├── smartparens-get-paired-expression-ruby-test.el ├── smartparens-insertion-specification-parser-test.el ├── smartparens-get-comment-bounds-test.el ├── smartparens-movement-test.el ├── smartparens-get-paired-expression-latex-test.el ├── smartparens-delayed-hook-test.el ├── smartparens-barf-test.el ├── smartparens-ess-test.el ├── smartparens-get-prefix-test.el ├── smartparens-cua-selection-test.el ├── smartparens-region-ok-test.el ├── smartparens-delete-pair-test.el ├── smartparens-get-stringlike-expression-elisp-test.el ├── smartparens-markdown-test.el ├── smartparens-elisp-test.el ├── smartparens-get-expression-test.el ├── smartparens-auctex-latex-test.el ├── smartparens-tex-mode-latex-test.el ├── smartparens-framework-test.el ├── smartparens-skip-closing-pair-test.el ├── smartparens-delete-selection-test.el ├── smartparens-swift-test.el ├── smartparens-show-mode-test.el ├── smartparens-python-test.el └── smartparens-rust-test.el ├── make-release.sh ├── Cask ├── smartparens-erlang.el ├── smartparens-unison.el ├── smartparens-racket.el ├── smartparens-go.el ├── sp-sublimetext-like.el ├── smartparens-coq.el ├── smartparens-text.el ├── smartparens-c.el ├── smartparens-clojure.el ├── smartparens-rst.el ├── smartparens-javascript.el ├── smartparens-ml.el ├── smartparens-scala.el ├── smartparens-lua.el ├── smartparens-markdown.el ├── smartparens-org.el ├── smartparens-swift.el ├── smartparens-haskell.el ├── smartparens-python.el └── smartparens-rust.el /.gitignore: -------------------------------------------------------------------------------- 1 | elpa 2 | *.elc 3 | *~* 4 | docs/_build 5 | .dir-locals-2.el 6 | .eask 7 | .cask 8 | .elsa 9 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-autobuild 3 | sphinxcontrib-emacs 4 | sphinx_rtd_theme 5 | rst 6 | -------------------------------------------------------------------------------- /images/smartparens-wrap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fuco1/smartparens/HEAD/images/smartparens-wrap.gif -------------------------------------------------------------------------------- /images/smartparens-insert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fuco1/smartparens/HEAD/images/smartparens-insert.gif -------------------------------------------------------------------------------- /images/smartparens-slurp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fuco1/smartparens/HEAD/images/smartparens-slurp.gif -------------------------------------------------------------------------------- /images/smartparens-navigate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fuco1/smartparens/HEAD/images/smartparens-navigate.gif -------------------------------------------------------------------------------- /smartparens-pkg.el: -------------------------------------------------------------------------------- 1 | (define-package "smartparens" "1.11.0" "Automatic insertion, wrapping and paredit-like navigation with user defined pairs." 2 | '((dash "2.13.0"))) 3 | -------------------------------------------------------------------------------- /dev/README.md: -------------------------------------------------------------------------------- 1 | # dev 2 | 3 | Bunch of development notes and proposals. Mostly of interest to the author and people involved with the project, but also to describe and review future API changes. 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [Fuco1] 4 | patreon: matusgoljer 5 | custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A5PMGVKCQBT88 6 | -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;;; Directory Local Variables 2 | ;;; For more information see (info "(emacs) Directory Variables") 3 | 4 | ((nil . 5 | ((bug-reference-url-format . "https://github.com/Fuco1/smartparens/issues/%s")))) 6 | -------------------------------------------------------------------------------- /docs/example-configuration.rst: -------------------------------------------------------------------------------- 1 | .. _example-configuration: 2 | 3 | Example configuration 4 | ======= 5 | 6 | The latest working configuration of the author can be found at `GitHub `_. Before looking at it, have a look at the `default-configuration `_ for things already set up for you! 7 | -------------------------------------------------------------------------------- /dev/skip-function.org: -------------------------------------------------------------------------------- 1 | * use cases 2 | 3 | - skipping out of active pairs 4 | - this is easy, because we have the data about the pair from the 5 | overlay. Can work both inside and at the end 6 | - skipping out of inactive pairs 7 | - when point is at the end and the closing delim is inserted 8 | - when point is somewhere inside, the expression is properly 9 | balanced, and the closing delim is inserted 10 | 11 | * problems 12 | 13 | - string-like delims 14 | - we need to be able to detect if we are skipping out or into such a 15 | structure 16 | - multi-char pairs. Is this worth it? 17 | -------------------------------------------------------------------------------- /test/smartparens-lua-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | (require 'lua-mode) 3 | 4 | (ert-deftest sp-test-lua-complete-block-in-code () 5 | "When inserting the beginning of a block, insert the matching end" 6 | (sp-test-with-temp-buffer "|" 7 | (lua-mode) 8 | (execute-kbd-macro "for ") 9 | (should (equal (buffer-string) "for do 10 | end")))) 11 | 12 | 13 | (ert-deftest sp-test-lua-no-complete-block-in-comment () 14 | "When inserting a beginning of block keyword in a comment, don't autocomplete" 15 | (sp-test-with-temp-buffer "-- |" 16 | (lua-mode) 17 | (execute-kbd-macro "for ") 18 | (should (equal (buffer-string) "-- for ")))) 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Expected behavior 2 | 3 | 4 | 5 | ## Actual behavior 6 | 7 | 8 | 9 | ## Steps to reproduce the problem 10 | 11 | 12 | 13 | ## Backtraces if necessary (`M-x toggle-debug-on-error`) 14 | 15 | 16 | 17 | ## Environment & version information 18 | 19 | **In recent enough `smartparens` you can call `M-x sp-describe-system` to generate this report**. Please fill manually what we could not detect automatically. Edit the output as you see fit to protect your privacy. 20 | 21 | - `smartparens` version: 22 | - Active major-mode: 23 | - Emacs version (`M-x emacs-version`): 24 | - Spacemacs/Evil/Other starterkit (specify which)/Vanilla: 25 | - OS: 26 | -------------------------------------------------------------------------------- /make-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | if [ -z $1 ]; then 4 | echo "Usage: ./make-release.sh " 5 | exit 1 6 | fi 7 | 8 | VERSION=$1 9 | 10 | if git tag | grep -q "$VERSION" ; then 11 | echo "Version $VERSION already exists; use \`git tag -d $VERSION' to remove the tag" 12 | exit 1 13 | fi 14 | 15 | echo -n "Updating Cask... " 16 | SEDSCRIPT='s/(package .*?)("[0-9.]+")/\1'"\"${VERSION}\""'/' 17 | sed -i -re "$SEDSCRIPT" Cask 18 | echo "done" 19 | 20 | echo -n "Updating pkg file... " 21 | cask pkg-file 22 | echo "done" 23 | 24 | echo -n "Create release commit... " 25 | git add Cask 26 | git add smartparens-pkg.el 27 | git commit -m "Release $VERSION" 28 | echo "done" 29 | 30 | echo -n "Updating git tags... " 31 | git tag -f "$VERSION" 32 | echo "done" 33 | -------------------------------------------------------------------------------- /dev/actions.org: -------------------------------------------------------------------------------- 1 | * Actions, rename to Permissions 2 | ** insert 3 | Insert the closing delimiter when the opening delimiter or the trigger is inserted (in case of trigger, replace it with the open-close pair) 4 | ** wrap 5 | If a region is active, allow wraping it with the pair 6 | ** autoskip 7 | Skip over the closing delimiter if it is typed in an active sexp at the end or according to =sp-autoskip-closing-pair=. 8 | ** escape 9 | Allow autoescaping of this delimiter in string contexts 10 | ** navigate 11 | Enable this pair for navigation 12 | ** parse 13 | Enable this pair for parsing (that is, non-interactive calls) 14 | TODO: Do we want this to be separate from navigate? 15 | ** strict 16 | Enable strictness checks for this pair (if =smartparens-strict-mode= is enabled) 17 | ** highlight 18 | Enable pair for highlighting (if =show-smartparens-mode= is enabled) 19 | -------------------------------------------------------------------------------- /test/smartparens-get-paired-expression-c-test.el: -------------------------------------------------------------------------------- 1 | (defun sp-test--paired-expression-parse-in-c (initial result &optional back) 2 | (sp-test-with-temp-buffer initial 3 | (c-mode) 4 | (should (equal (sp-get-paired-expression back) result)))) 5 | 6 | (ert-deftest sp-test-paired-expression-parse-in-c nil 7 | (let ((sp-pairs '((t . ((:open "(" :close ")" :actions (insert wrap autoskip navigate)) 8 | (:open "{" :close "}" :actions (insert wrap autoskip navigate)) 9 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)) 10 | (:open "/*" :close "*/" :actions (insert wrap autoskip navigate))))))) 11 | (sp-test--paired-expression-parse-in-c "asd |/* adasdad */" '(:beg 5 :end 18 :op "/*" :cl "*/" :prefix "" :suffix "")) 12 | (sp-test--paired-expression-parse-in-c "asd /* adasdad */|" '(:beg 5 :end 18 :op "/*" :cl "*/" :prefix "" :suffix "") t) 13 | )) 14 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source melpa) 2 | (source gnu) 3 | 4 | (package "smartparens" "1.11.0" 5 | "Automatic insertion, wrapping and paredit-like navigation with user defined pairs.") 6 | 7 | (depends-on "cl-lib" "0.3") 8 | (depends-on "dash" "2.13.0") 9 | 10 | (development 11 | (depends-on "f") 12 | (depends-on "yasnippet") 13 | (depends-on "ert-runner") 14 | (depends-on "undercover") 15 | (depends-on "shut-up") 16 | (depends-on "ruby-mode") 17 | (depends-on "racket-mode") 18 | (depends-on "scala-mode") 19 | (depends-on "rust-mode") 20 | (depends-on "swift-mode") 21 | (depends-on "auctex") 22 | (depends-on "clojure-mode") 23 | (depends-on "lua-mode") 24 | (depends-on "js2-mode") 25 | (depends-on "ess") 26 | (depends-on "tuareg") 27 | (depends-on "scala-mode") 28 | (depends-on "elixir-mode") 29 | (depends-on "haskell-mode") 30 | (depends-on "markdown-mode") 31 | (depends-on "hungry-delete") 32 | (depends-on "evil") 33 | (depends-on "crystal-mode") 34 | (depends-on "go-mode")) 35 | -------------------------------------------------------------------------------- /test/smartparens-go-test.el: -------------------------------------------------------------------------------- 1 | (require 'go-mode) 2 | (require 'smartparens) 3 | 4 | (defun sp-test--paired-expression-parse-in-go (initial result &optional back) 5 | (sp-test-with-temp-buffer initial 6 | (go-mode) 7 | (should (equal (sp-get-paired-expression back) result)))) 8 | 9 | (ert-deftest sp-test-paired-expression-parse-in-go nil 10 | (let ((sp-pairs '((t . ((:open "(" :close ")" :actions (insert wrap autoskip navigate)) 11 | (:open "{" :close "}" :actions (insert wrap autoskip navigate)) 12 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)) 13 | (:open "/*" :close "*/" :actions (insert wrap autoskip navigate))))))) 14 | (sp-test--paired-expression-parse-in-go "asd |/* adasdad */" '(:beg 5 :end 18 :op "/*" :cl "*/" :prefix "" :suffix "")) 15 | (sp-test--paired-expression-parse-in-go "asd /* adasdad */|" '(:beg 5 :end 18 :op "/*" :cl "*/" :prefix "" :suffix "") t))) 16 | 17 | (ert-deftest sp-test-go-slurp () 18 | "Deleting a region containing a rust function definition." 19 | (sp-test-with-temp-buffer "(|foo).bar" 20 | (go-mode) 21 | (call-interactively 'sp-slurp-hybrid-sexp) 22 | (should (equal (buffer-string) "(foo.bar)")))) 23 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | strategy: 8 | matrix: 9 | emacs_version: 10 | - '27.1' 11 | - '27.2' 12 | - '28.1' 13 | - '28.2' 14 | - '29.1' 15 | - '29.2' 16 | - '29.3' 17 | - '29.4' 18 | - 'snapshot' 19 | include: 20 | - emacs_version: 'snapshot' 21 | allow_failure: true 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: purcell/setup-emacs@master 25 | with: 26 | version: ${{ matrix.emacs_version }} 27 | - uses: actions/setup-python@v5 28 | - uses: conao3/setup-cask@master 29 | 30 | - name: Install dependencies 31 | run: 'cask install' 32 | 33 | - name: Run tests 34 | if: matrix.allow_failure != true 35 | run: | 36 | cask exec ert-runner --reporter ert+duration 37 | cask exec emacs --eval "(setq byte-compile-error-on-warn t)" -L . --batch -f batch-byte-compile smartparens.el smartparens-*[^pkg].el 38 | 39 | - name: Run tests (allow failure) 40 | if: matrix.allow_failure == true 41 | run: | 42 | cask exec ert-runner --reporter ert+duration || true 43 | cask exec emacs --eval "(setq byte-compile-error-on-warn t)" -L . --batch -f batch-byte-compile smartparens.el smartparens-*[^pkg].el || true 44 | -------------------------------------------------------------------------------- /test/smarparents-clojure-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-clojure) 2 | (require 'clojure-mode) 3 | 4 | (sp-ert-deftest sp-test-clojure-wrap-with-prefix 5 | :let ((sp-pairs sp--test-basic-pairs)) 6 | :mode 'clojure-mode 7 | "Ensure correct wrap-pair over prefixed expressions." 8 | (sp-test-kbd-macro "|#{...}M" "(" "(|#{...}M)") 9 | (sp-test-kbd-macro "|^{:a 1}M" "(" "(|^{:a 1}M)") 10 | (sp-test-kbd-macro "|#(xyzzy 1 2 %)M" "(" "(|#(xyzzy 1 2 %)M)") 11 | (sp-test-kbd-macro "|#_(comment reader macro)M" "(" "(|#_(comment reader macro)M)") 12 | (sp-test-kbd-macro "|~unquote-meM" "(" "(|~unquote-meM)") 13 | (sp-test-kbd-macro "|`~'unquote-meM" "(" "(|`~'unquote-meM)") 14 | (sp-test-kbd-macro "|~@(splice-me)M" "(" "(|~@(splice-me)M)") 15 | (sp-test-kbd-macro "|`(quote-me)M" "(" "(|`(quote-me)M)") 16 | (sp-test-kbd-macro "|@(deref-me)M" "(" "(|@(deref-me)M)") 17 | (sp-test-kbd-macro "|@deref-meM" "(" "(|@deref-meM)") 18 | (sp-test-kbd-macro "|#?@(:clj [3 4] :cljs [5 6])M" "(" "(|#?@(:clj [3 4] :cljs [5 6])M)") 19 | (sp-test-kbd-macro "|#?(:clj Double/NaN 20 | :cljs js/NaN 21 | :default nil)M" "(" "(|#?(:clj Double/NaN 22 | :cljs js/NaN 23 | :default nil)M)")) 24 | 25 | (sp-ert-deftest sp-test-clojure-wrap-with-fence-prefix 26 | :let ((sp-pairs sp--test-basic-pairs)) 27 | :mode 'clojure-mode 28 | "Ensure correct wrap-pair over #-prefixed expressions." 29 | (sp-test-kbd-macro "|#\"...\"M" "(" "(#\"...\")") 30 | (sp-test-kbd-macro "|#~xyzzyM" "(" "(#~xyzzy)")) 31 | -------------------------------------------------------------------------------- /test/smartparens-search-fn-test.el: -------------------------------------------------------------------------------- 1 | (ert-deftest sp-test-search-backward-in-context/code/first-match-same () 2 | (sp-test-with-temp-elisp-buffer "f|oo bar baz" 3 | (should (equal (sp--search-forward-in-context "bar" nil t) 8)) 4 | (sp-buffer-equals "foo bar| baz"))) 5 | 6 | (ert-deftest sp-test-search-backward-in-context/code/first-match-different () 7 | (sp-test-with-temp-elisp-buffer "f|oo ; bar baz" 8 | (should (equal (sp--search-forward-in-context "bar" nil t) nil)) 9 | (sp-buffer-equals "f|oo ; bar baz"))) 10 | 11 | (ert-deftest sp-test-search-backward-in-context/code/second-match-same () 12 | (sp-test-with-temp-elisp-buffer "f|oo ; bar baz 13 | bar baz" 14 | (should (equal (sp--search-forward-in-context "bar" nil t) 18)) 15 | (sp-buffer-equals "foo ; bar baz 16 | bar| baz"))) 17 | 18 | (ert-deftest sp-test-search-backward-in-context/comment/first-match-same () 19 | (sp-test-with-temp-elisp-buffer ";f|oo bar baz" 20 | (should (equal (sp--search-forward-in-context "bar" nil t) 9)) 21 | (sp-buffer-equals ";foo bar| baz"))) 22 | 23 | (ert-deftest sp-test-search-backward-in-context/comment/first-match-different () 24 | (sp-test-with-temp-elisp-buffer ";f|oo 25 | bar baz" 26 | (should (equal (sp--search-forward-in-context "bar" nil t) nil)) 27 | (sp-buffer-equals ";f|oo 28 | bar baz"))) 29 | 30 | (ert-deftest sp-test-search-backward-in-context/comment/second-match-same () 31 | (sp-test-with-temp-elisp-buffer ";f|oo 32 | bar baz 33 | ; bar baz" 34 | (should (equal (sp--search-forward-in-context "bar" nil t) 19)) 35 | (sp-buffer-equals ";foo 36 | bar baz 37 | ; bar| baz"))) 38 | -------------------------------------------------------------------------------- /test/smartparens-ocaml-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | (require 'tuareg) 3 | 4 | (defun sp-test--ocaml-mode () 5 | (shut-up (tuareg-mode))) 6 | 7 | (ert-deftest sp-test-ocaml-forward-slurp-parenthesis-whitespace () 8 | "Ensure we don't add unwanted whitespace when slurping." 9 | (sp-test-with-temp-buffer "(|foo) List.map" 10 | (sp-test--ocaml-mode) 11 | (sp-forward-slurp-sexp 2) 12 | (should (equal (buffer-string) "(foo List.map)")))) 13 | 14 | (ert-deftest sp-test-ocaml-backward-slurp-parenthesis-whitespace () 15 | "Ensure we don't add unwanted whitespace when slurping." 16 | (sp-test-with-temp-buffer "List.map (|foo)" 17 | (sp-test--ocaml-mode) 18 | (sp-backward-slurp-sexp 2) 19 | (should (equal (buffer-string) "(List.map foo)")))) 20 | 21 | (ert-deftest sp-test-ocaml-forward-slurp-square-bracket-whitespace () 22 | "Ensure we don't add unwanted whitespace when slurping." 23 | (sp-test-with-temp-buffer "[|foo] List.map" 24 | (sp-test--ocaml-mode) 25 | (sp-forward-slurp-sexp 2) 26 | (should (equal (buffer-string) "[foo List.map]")))) 27 | 28 | (ert-deftest sp-test-ocaml-backward-slurp-square-bracket-whitespace () 29 | "Ensure we don't add unwanted whitespace when slurping." 30 | (sp-test-with-temp-buffer "List.map [|foo]" 31 | (sp-test--ocaml-mode) 32 | (sp-backward-slurp-sexp 2) 33 | (should (equal (buffer-string) "[List.map foo]")))) 34 | 35 | (ert-deftest sp-test-ocaml-splice-sexp-tilde () 36 | "Ensure ~ isn't removed when removing parentheses" 37 | (sp-test-with-temp-buffer "let foo ~(|x) = x" 38 | (sp-test--ocaml-mode) 39 | (sp-splice-sexp) 40 | (should (equal (buffer-string) "let foo ~x = x")))) 41 | -------------------------------------------------------------------------------- /test/smartparens-rst-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-rst) 2 | (require 'rst) 3 | 4 | (ert-deftest sp-test-rst-insert-quote-dont-escape-quote nil 5 | "In text modes where ' and \" are not string syntax, do not 6 | escape them on the top level." 7 | (let ((sp-pairs 8 | '((t 9 | (:open "\"" :close "\"" 10 | :actions (insert wrap autoskip navigate) 11 | :post-handlers (sp-escape-quotes-after-insert)) 12 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)))))) 13 | (sp-test-with-temp-buffer "foo | bar" 14 | (rst-mode) 15 | (execute-kbd-macro "\"") 16 | (sp-buffer-equals "foo \"|\" bar")))) 17 | 18 | (ert-deftest sp-test-rst-insert-quote-dont-escape-in-contraction nil 19 | "Do not escape ' after a word when it is used as a contraction" 20 | (let ((sp-pairs 21 | '((t 22 | (:open "'" :close "'" 23 | :actions (insert wrap autoskip navigate escape) 24 | :unless (sp-in-string-quotes-p sp-point-after-word-p) 25 | :post-handlers (sp-escape-wrapped-region sp-escape-quotes-after-insert)) 26 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)))))) 27 | (sp-test-with-temp-buffer "foo| bar" 28 | (rst-mode) 29 | (execute-kbd-macro "'s") 30 | (sp-buffer-equals "foo's| bar")))) 31 | 32 | (ert-deftest sp-test-rst-no-double-underscore-after-ref nil 33 | "When turning the backtick reference to a link by appending an 34 | underscore, do not double the underscore automatically." 35 | (sp-test-with-temp-buffer "foo `bar`|" 36 | (rst-mode) 37 | (execute-kbd-macro "_") 38 | (sp-buffer-equals "foo `bar`_|"))) 39 | -------------------------------------------------------------------------------- /test/smartparens-slurp-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | 3 | (ert-deftest sp-test-js-slurp-excludes-semicolon () 4 | (sp-test-with-temp-buffer "var foo = bar(|)baz;" 5 | (js-mode) 6 | (sp-slurp-hybrid-sexp) 7 | (should (equal (buffer-string) "var foo = bar(baz);")))) 8 | 9 | (ert-deftest sp-test-js-slurp-curly-paren () 10 | (sp-test-with-temp-buffer "while (true) {|} 11 | bar;" 12 | (js-mode) 13 | (sp-slurp-hybrid-sexp) 14 | (should (equal (buffer-string) "while (true) { 15 | bar; 16 | }")))) 17 | 18 | (ert-deftest sp-test-python-slurp-exclude-colon () 19 | (sp-test-with-temp-buffer "if bar(|)foo:" 20 | (shut-up (python-mode)) 21 | (sp-slurp-hybrid-sexp) 22 | (should (equal (buffer-string) "if bar(foo):")))) 23 | 24 | (ert-deftest sp-test-python-slurp-include-dot () 25 | (sp-test-with-temp-buffer "(|foo).bar" 26 | (shut-up (python-mode)) 27 | (sp-slurp-hybrid-sexp) 28 | (should (equal (buffer-string) "(foo.bar)")))) 29 | 30 | (ert-deftest sp-test-c++-slurp-include-semicolon () 31 | (sp-test-with-temp-buffer "class foo {| 32 | public: 33 | int a; 34 | }; 35 | int b = 7;" 36 | (c++-mode) 37 | (sp-slurp-hybrid-sexp) 38 | (should (equal (buffer-string) "class foo { 39 | public: 40 | int a; 41 | int b = 7; 42 | };")))) 43 | 44 | (ert-deftest sp-test-rust-slurp-include-dot () 45 | (sp-test-with-temp-buffer "(foo|).bar" 46 | (rust-mode) 47 | (sp-slurp-hybrid-sexp) 48 | (should (equal (buffer-string) "(foo.bar)")))) 49 | 50 | (ert-deftest sp-test-js-slurp-from-closing-paren () 51 | (sp-test-with-temp-buffer "if (foo) { 52 | x = 1; 53 | |} 54 | y = baz(); 55 | " 56 | (js-mode) 57 | (sp-slurp-hybrid-sexp) 58 | (should (equal (buffer-string) "if (foo) { 59 | x = 1; 60 | y = baz(); 61 | } 62 | ")))) 63 | -------------------------------------------------------------------------------- /test/smartparens-get-suffix-test.el: -------------------------------------------------------------------------------- 1 | ;; #488 2 | (ert-deftest sp-test-get-suffix-short-suffix () 3 | (let ((sp-sexp-suffix '((emacs-lisp-mode regexp "'-?")))) 4 | (sp-test-with-temp-elisp-buffer "(foo)'" 5 | (should (equal (sp--get-suffix 6 "(") "'"))))) 6 | 7 | (ert-deftest sp-test-get-suffix-full-suffix () 8 | (let ((sp-sexp-suffix '((emacs-lisp-mode regexp "'-?")))) 9 | (sp-test-with-temp-elisp-buffer "(foo)'-" 10 | (should (equal (sp--get-suffix 6 "(") "'-"))))) 11 | 12 | (ert-deftest sp-test-get-suffix-nonsense-suffix () 13 | (let ((sp-sexp-suffix '((emacs-lisp-mode regexp "'-?")))) 14 | (sp-test-with-temp-elisp-buffer "(foo)-" 15 | (should (equal (sp--get-suffix 6 "(") ""))))) 16 | 17 | (ert-deftest sp-test-get-suffix-no-suffix () 18 | (let ((sp-sexp-suffix '((emacs-lisp-mode regexp "'-?")))) 19 | (sp-test-with-temp-elisp-buffer "(foo)" 20 | (should (equal (sp--get-suffix 6 "(") ""))))) 21 | 22 | ;; 664 23 | (ert-deftest sp-test-get-suffix-which-is-a-pair-in-text-mode () 24 | (let ((sp-pairs '((t (:open "«" :close "»" :actions (navigate)))))) 25 | (sp-test-with-temp-buffer "«asdasd»|«asdasd»" 26 | (text-mode) 27 | (should (equal (sp--get-suffix (point) "«") ""))))) 28 | 29 | (ert-deftest sp-test-get-suffix-always-return-string () 30 | "Previously in case of a pair-specific suffix we could return 31 | nil if there was no match." 32 | (let ((sp-sexp-suffix '((emacs-lisp-mode regexp "\\(?:aaa\\)")))) 33 | (sp-test-with-temp-elisp-buffer "((abc)|aaa) asd" 34 | (let ((sp-pairs '((t (:open "(" :close ")" :actions (insert wrap autoskip navigate))) 35 | (emacs-lisp-mode (:open "(" :close ")" :actions (insert wrap autoskip navigate) :suffix "x"))))) 36 | (sp--update-local-pairs) 37 | (should (equal (sp--get-suffix (point) "(") "")))))) 38 | -------------------------------------------------------------------------------- /test/smartparens-settings-sp-pair-test.el: -------------------------------------------------------------------------------- 1 | (ert-deftest sp-test-add-global-pair () 2 | (let ((sp-pairs nil)) 3 | (sp-pair "(" ")") 4 | (should (equal sp-pairs '((t (:open "(" :close ")" :actions (wrap insert autoskip navigate)))))))) 5 | 6 | (ert-deftest sp-test-add-global-pair-with-a-when-condition () 7 | (let ((sp-pairs nil)) 8 | (sp-pair "(" ")" :when '(ignore)) 9 | (should (equal sp-pairs '((t (:open "(" :close ")" 10 | :actions (wrap insert autoskip navigate) 11 | :when (ignore)))))))) 12 | 13 | (ert-deftest sp-test-remove-global-pair-when-condition () 14 | (let ((sp-pairs '((t (:open "(" :close ")" 15 | :actions (wrap insert autoskip navigate) 16 | :when (ignore)))))) 17 | (sp-pair "(" ")" :when nil) 18 | (should (equal sp-pairs '((t (:open "(" :close ")" 19 | :actions (wrap insert autoskip navigate) 20 | :when nil))))))) 21 | 22 | (ert-deftest sp-test-replace-global-pair-actions () 23 | (let ((sp-pairs '((t (:open "(" :close ")" 24 | :actions (wrap insert autoskip navigate) 25 | :when (ignore)))))) 26 | (sp-pair "(" ")" :actions '(wrap insert)) 27 | (should (equal sp-pairs '((t (:open "(" :close ")" 28 | :actions (wrap insert) 29 | :when nil))))))) 30 | 31 | (ert-deftest sp-test-remove-global-pair-nonexisting-when-condition () 32 | (let ((sp-pairs '((t (:open "(" :close ")" 33 | :actions (wrap insert autoskip navigate)))))) 34 | (sp-pair "(" ")" :when nil) 35 | (should (equal sp-pairs '((t (:open "(" :close ")" 36 | :actions (wrap insert autoskip navigate)))))))) 37 | -------------------------------------------------------------------------------- /smartparens-erlang.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-erlang.el --- Additional configuration for erlang-mode. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2022 Johnny Ruiz 4 | 5 | ;; Created: 6 September 2022 6 | ;; Keywords: abbrev convenience editing 7 | ;; URL: https://github.com/Fuco1/smartparens 8 | 9 | ;; This file is not part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Smartparens. 14 | 15 | ;; Smartparens is free software; you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | 20 | ;; Smartparens is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Smartparens. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; This file provides some additional configuration for Erlang. To use 31 | ;; it, simply add: 32 | ;; 33 | ;; (require 'smartparens-config) 34 | ;; 35 | ;; alternatively, you can explicitly load these preferences: 36 | ;; 37 | ;; (require 'smartparens-erlang) 38 | ;; 39 | ;; in your configuration. 40 | 41 | ;; For more info, see github readme at 42 | ;; https://github.com/Fuco1/smartparens 43 | 44 | ;;; Code: 45 | (require 'smartparens) 46 | 47 | (declare-function erlang-mode "erlang-mode") 48 | 49 | (sp-with-modes '(erlang-mode erlang-ts-mode) 50 | (sp-local-pair "`" "'" 51 | :when '(sp-in-comment-p)) 52 | (sp-local-pair "<<" ">>") 53 | (sp-local-pair "#{" "}")) 54 | 55 | (provide 'smartparens-erlang) 56 | ;;; smartparens-erlang.el ends here 57 | -------------------------------------------------------------------------------- /test/smartparens-text-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-text) 2 | (require 'message) 3 | 4 | (ert-deftest sp-test-text-mode-insert-emoticon-smiley-strict-mode () 5 | "#713" 6 | (sp-test-with-temp-buffer "|" 7 | (message-mode) 8 | (smartparens-strict-mode 1) 9 | (execute-kbd-macro ":)") 10 | (sp-buffer-equals ":)"))) 11 | 12 | (ert-deftest sp-test-text-mode-insert-emoticon-smiley-with-nose-strict-mode () 13 | "#713" 14 | (sp-test-with-temp-buffer "|" 15 | (message-mode) 16 | (smartparens-strict-mode 1) 17 | (execute-kbd-macro ":-)") 18 | (sp-buffer-equals ":-)"))) 19 | 20 | (ert-deftest sp-test-text-mode-insert-emoticon-frowny-strict-mode () 21 | "#713" 22 | (sp-test-with-temp-buffer "|" 23 | (message-mode) 24 | (smartparens-strict-mode 1) 25 | (execute-kbd-macro ":(") 26 | (sp-buffer-equals ":("))) 27 | 28 | (ert-deftest sp-test-text-mode-insert-emoticon-frowny-with-nose-strict-mode () 29 | "#713" 30 | (sp-test-with-temp-buffer "|" 31 | (message-mode) 32 | (smartparens-strict-mode 1) 33 | (execute-kbd-macro ":-(") 34 | (sp-buffer-equals ":-("))) 35 | 36 | (ert-deftest sp-test-text-mode-skip-emoticon-when-navigating () 37 | "#713" 38 | (sp-test-with-temp-buffer "|(foo :) bar :( baz)" 39 | (message-mode) 40 | (sp-forward-sexp) 41 | (sp-buffer-equals "(foo :) bar :( baz)|"))) 42 | 43 | (ert-deftest sp-test-text-mode-wrap-emoticons-strict-mode () 44 | "#713" 45 | (sp-test-with-temp-buffer "| foo :) bar :( baz M" 46 | (message-mode) 47 | (smartparens-strict-mode 1) 48 | (execute-kbd-macro "(") 49 | (sp-buffer-equals "(| foo :) bar :( baz M)"))) 50 | 51 | (ert-deftest sp-test-text-mode-kill-region-with-emoticons-strict-mode () 52 | "#713" 53 | (sp-test-with-temp-buffer "foo | foo :) bar :( baz M" 54 | (message-mode) 55 | (smartparens-strict-mode 1) 56 | (call-interactively 'sp-kill-region) 57 | (sp-buffer-equals "foo |"))) 58 | -------------------------------------------------------------------------------- /test/smartparens-haskell-test.el: -------------------------------------------------------------------------------- 1 | (require 'haskell) 2 | (require 'smartparens-haskell) 3 | 4 | ;; #710 5 | (ert-deftest sp-test-haskell-allow-deleting-quote-at-end-of-symbol () 6 | (sp-test-with-temp-buffer "myFunction'|" 7 | (haskell-mode) 8 | (smartparens-strict-mode 1) 9 | (sp-backward-delete-char) 10 | (sp-buffer-equals "myFunction|"))) 11 | 12 | ;; #710 13 | (ert-deftest sp-test-haskell-ignore-apostrophe-when-looking-for-sexp-when-it-is-used-as-suffix () 14 | (sp-test-with-temp-buffer "test c d = myFunction' c + (myFunct|ion' d)" 15 | (haskell-mode) 16 | (sp-get (sp-get-sexp) 17 | (should (equal :op "("))) 18 | (sp-get (sp-get-enclosing-sexp) 19 | (should (equal :op "("))))) 20 | 21 | ;; #710 22 | (ert-deftest sp-test-haskell-splice-sexp-when-there-is-trailing-quote () 23 | (sp-test-with-temp-buffer "test c d = myFunction' c + (myFunct|ion' d)" 24 | (haskell-mode) 25 | (sp-splice-sexp) 26 | (sp-buffer-equals "test c d = myFunction' c + myFunct|ion' d"))) 27 | 28 | ;; #710 29 | (ert-deftest sp-test-haskell-unwrap-sexp-when-there-is-trailing-quote () 30 | (sp-test-with-temp-buffer "test c d = myFunction' c + (myFunct|ion' d)" 31 | (haskell-mode) 32 | (sp-unwrap-sexp) 33 | (sp-buffer-equals "test c d = myFunction' c + myFunct|ion' d"))) 34 | 35 | ;; #710 36 | (ert-deftest sp-test-haskell-splice-char-sexp () 37 | (sp-test-with-temp-buffer "'|a'" 38 | (haskell-mode) 39 | (sp-splice-sexp) 40 | (sp-buffer-equals "|a"))) 41 | 42 | ;; #710 43 | (ert-deftest sp-test-haskell-unwrap-char-sexp () 44 | (sp-test-with-temp-buffer "'|a'" 45 | (haskell-mode) 46 | (sp-unwrap-sexp) 47 | (sp-buffer-equals "|a"))) 48 | 49 | (ert-deftest sp-test-haskell-sp-backward-kill-words-respects-pairs-in-strict-mode () 50 | (sp-test-with-temp-buffer "foo a = foldr (+) []| b" 51 | (haskell-mode) 52 | (smartparens-strict-mode 1) 53 | (sp-backward-kill-word 1) 54 | (sp-buffer-equals "foo a = | (+) [] b"))) 55 | -------------------------------------------------------------------------------- /smartparens-unison.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-unison.el --- Additional configuration for Unison -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2022 Joseph Morag 4 | 5 | ;; Author: Joseph Morag 6 | ;; Maintainer: Joseph Morag 7 | ;; Created: 04 December 2022 8 | ;; Keywords: smartparens, unison 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Unison. 33 | ;; To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-unison) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (sp-with-modes '(unisonlang-mode) 51 | ;; Disable ' because it is used as a shortcut to wrap a value in 52 | ;; lambda () -> value 53 | ;; to make it lazy 54 | (sp-local-pair "'" nil :actions nil)) 55 | 56 | (provide 'smartparens-unison) 57 | ;;; smartparens-unison.el ends here 58 | -------------------------------------------------------------------------------- /smartparens-racket.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-racket.el --- Additional configuration for Racket based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015, 2018 Vikraman Choudhury 4 | 5 | ;; Author: Vikraman Choudhury 6 | ;; Maintainer: Vikraman Choudhury 7 | ;; Created: 26 Oct 2015 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Racket based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-racket) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (sp-with-modes '(racket-mode racket-repl-mode) 51 | (sp-local-pair "`" nil :actions nil) 52 | (sp-local-pair "'" nil :actions nil) 53 | (sp-local-pair "#|" "|#")) 54 | 55 | (provide 'smartparens-racket) 56 | ;;; smartparens-racket.el ends here 57 | -------------------------------------------------------------------------------- /test/smartparens-javascript-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-javascript) 2 | (require 'js2-mode) 3 | 4 | (defun sp-test--javascript-mode () 5 | "Helper" 6 | (shut-up (js-mode))) 7 | 8 | (ert-deftest sp-test-javascript-slurp-whitespace () 9 | "Ensure we don't add unwanted whitespace when slurping." 10 | (sp-test-with-temp-buffer "(|)foo.bar()" 11 | (sp-test--javascript-mode) 12 | (sp-forward-slurp-sexp) 13 | (sp-forward-slurp-sexp) 14 | (should (equal (buffer-string) "(foo.bar)()")))) 15 | 16 | (ert-deftest sp-test-js2-reindent-after-kill () 17 | (sp-test-with-temp-buffer "function f () { 18 | | 19 | return 42; // 2 spaces of indentation 20 | } 21 | " 22 | (shut-up (js2-mode)) 23 | (sp-kill-hybrid-sexp 1) 24 | (sp-buffer-equals "function f () { 25 | |return 42; // 2 spaces of indentation 26 | } 27 | "))) 28 | 29 | (ert-deftest sp-test-js2-jsx-html-element-as-sexp () 30 | (sp-test-with-temp-buffer "function render() { 31 | return |Top; 32 | } 33 | " 34 | (shut-up (js2-jsx-mode)) 35 | (sp-forward-sexp) 36 | (sp-buffer-equals "function render() { 37 | return Top|; 38 | } 39 | ") 40 | (sp-backward-sexp) 41 | (sp-buffer-equals "function render() { 42 | return |Top; 43 | } 44 | "))) 45 | 46 | (ert-deftest sp-test-javascript-skip-arrow-fn-bracket () 47 | "#872" 48 | (sp-test-with-temp-buffer "|const test = () => { 49 | console.log('test') 50 | }M" 51 | (sp-test--javascript-mode) 52 | (call-interactively 'sp-kill-region) 53 | (should (equal (buffer-string) "")))) 54 | 55 | (ert-deftest sp-test-javascript-skip-arrow-fn-bracket-region-ok () 56 | "#872 The region should not be OK because it contains unclosed bracket. 57 | 58 | Before, the > character caused it to skip into the `console' 59 | token over the bracket and this made the region appear OK." 60 | (sp-test-with-temp-buffer "|const test = () => {M 61 | console.log('test') 62 | }" 63 | (sp-test--javascript-mode) 64 | (should (not (sp-region-ok-p (region-beginning) (region-end)))))) 65 | -------------------------------------------------------------------------------- /test/smartparens-get-stringlike-expression-python-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-python) 2 | 3 | (defmacro sp-test-with-temp-python-buffer (initial &rest forms) 4 | (declare (indent 1) 5 | (debug (form body))) 6 | `(sp-test-with-temp-buffer ,initial 7 | (shut-up (python-mode)) 8 | ,@forms)) 9 | 10 | (ert-deftest sp-test--python-get-thing-which-is-string-inside-string () 11 | (sp-test-with-temp-python-buffer "\"foo bar | 'baz qux' fux\"" 12 | (should (equal (sp-get-thing) '(:beg 11 :end 20 :op "'" :cl "'" :prefix "" :suffix "")))) 13 | 14 | (sp-test-with-temp-python-buffer "\"foo bar 'baz qux' | fux\"" 15 | (should (equal (sp-get-thing t) '(:beg 10 :end 19 :op "'" :cl "'" :prefix "" :suffix ""))))) 16 | 17 | (ert-deftest sp-test--python-get-expression-which-is-string-inside-string () 18 | (sp-test-with-temp-python-buffer "\"foo bar | 'baz qux' fux\"" 19 | (should (equal (sp-get-expression) '(:beg 11 :end 20 :op "'" :cl "'" :prefix "" :suffix "")))) 20 | 21 | (sp-test-with-temp-python-buffer "\"foo bar 'baz qux' | fux\"" 22 | (should (equal (sp-get-expression t) '(:beg 10 :end 19 :op "'" :cl "'" :prefix "" :suffix ""))))) 23 | 24 | (ert-deftest sp-test--python-get-stringlike-expression-inside-string () 25 | (sp-test-with-temp-python-buffer "\"foo bar | 'baz qux' fux\"" 26 | (should (equal (sp-get-stringlike-expression) '(:beg 11 :end 20 :op "'" :cl "'" :prefix "" :suffix "")))) 27 | 28 | (sp-test-with-temp-python-buffer "\"foo bar 'baz qux' | fux\"" 29 | (should (equal (sp-get-stringlike-expression t) '(:beg 10 :end 19 :op "'" :cl "'" :prefix "" :suffix ""))))) 30 | 31 | (ert-deftest sp-test--python-get-stringlike-or-textmode-expression-inside-string () 32 | (sp-test-with-temp-python-buffer "\"foo bar | 'baz qux' fux\"" 33 | (should (equal (sp-get-stringlike-or-textmode-expression) '(:beg 11 :end 20 :op "'" :cl "'" :prefix "" :suffix "")))) 34 | 35 | (sp-test-with-temp-python-buffer "\"foo bar 'baz qux' | fux\"" 36 | (should (equal (sp-get-stringlike-or-textmode-expression t) '(:beg 10 :end 19 :op "'" :cl "'" :prefix "" :suffix ""))))) 37 | -------------------------------------------------------------------------------- /smartparens-go.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-go.el --- Additional configuration for go-mode. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2022 Jimmy Yuen Ho Wong 4 | 5 | ;; Created: 10 June 2022 6 | ;; Keywords: abbrev convenience editing 7 | ;; URL: https://github.com/Fuco1/smartparens 8 | 9 | ;; This file is not part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Smartparens. 14 | 15 | ;; Smartparens is free software; you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | 20 | ;; Smartparens is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Smartparens. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; This file provides some additional configuration for Go. To use 31 | ;; it, simply add: 32 | ;; 33 | ;; (require 'smartparens-config) 34 | ;; 35 | ;; alternatively, you can explicitly load these preferences: 36 | ;; 37 | ;; (require 'smartparens-go) 38 | ;; 39 | ;; in your configuration. 40 | 41 | ;; For more info, see github readme at 42 | ;; https://github.com/Fuco1/smartparens 43 | 44 | ;;; Code: 45 | (require 'smartparens) 46 | 47 | (declare-function go-mode "go-mode") 48 | (declare-function go-ts-mode "go-ts-mode") 49 | 50 | (sp-with-modes '(go-mode go-ts-mode) 51 | (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET"))) 52 | (sp-local-pair "/*" "*/" :post-handlers '(("| " "SPC") 53 | ("* ||\n[i]" "RET")))) 54 | 55 | ;; Go has no sexp suffices. This fixes slurping 56 | ;; (|foo).bar -> (foo.bar) 57 | (add-to-list 'sp-sexp-suffix (list #'go-mode 'regexp "")) 58 | (add-to-list 'sp-sexp-suffix (list #'go-ts-mode 'regexp "")) 59 | 60 | (provide 'smartparens-go) 61 | 62 | ;;; smartparens-go.el ends here 63 | -------------------------------------------------------------------------------- /test/smartparens-advice-test.el: -------------------------------------------------------------------------------- 1 | ;;; Tests for advices and compat with external packages 2 | 3 | (require 'yasnippet) 4 | (require 'hippie-exp) 5 | 6 | ;; These macros are copied from yasnippet-tests.el 7 | (progn 8 | (defmacro yas-with-snippet-dirs (dirs &rest body) 9 | (declare (indent defun) (debug t)) 10 | `(yas-call-with-snippet-dirs 11 | ,dirs #'(lambda () ,@body))) 12 | 13 | (defun yas-make-file-or-dirs (ass) 14 | (let ((file-or-dir-name (car ass)) 15 | (content (cdr ass))) 16 | (cond ((listp content) 17 | (make-directory file-or-dir-name 'parents) 18 | (let ((default-directory (concat default-directory "/" file-or-dir-name))) 19 | (mapc #'yas-make-file-or-dirs content))) 20 | ((stringp content) 21 | (with-temp-buffer 22 | (insert content) 23 | (write-region nil nil file-or-dir-name nil 'nomessage))) 24 | (t 25 | (message "[yas] oops don't know this content"))))) 26 | 27 | (defun yas-call-with-snippet-dirs (dirs fn) 28 | (let* ((default-directory (make-temp-file "yasnippet-fixture" t)) 29 | (yas-snippet-dirs (mapcar (lambda (d) (expand-file-name (car d))) dirs))) 30 | (with-temp-message "" 31 | (unwind-protect 32 | (progn 33 | (mapc #'yas-make-file-or-dirs dirs) 34 | (funcall fn)) 35 | (when (>= emacs-major-version 24) 36 | (delete-directory default-directory 'recursive))))))) 37 | 38 | (ert-deftest sp-test-advice--hippie-no-pairing-if-sexp-already-exists () 39 | "Test that after hippie expand expands a yasnippet template it 40 | won't add an extra closing paren if the snippet already provides 41 | it." 42 | (yas-with-snippet-dirs 43 | '((".emacs.d/snippets" 44 | ("emacs-lisp-mode" ("defun" . "(defun hello ($0))")))) 45 | (let ((hippie-expand-try-functions-list 46 | '(yas-hippie-try-expand))) 47 | (sp-test-with-temp-elisp-buffer "defun|" 48 | (yas-reload-all) 49 | (yas-minor-mode 1) 50 | (call-interactively 'hippie-expand) 51 | (sp-buffer-equals "(defun hello (|))"))))) 52 | -------------------------------------------------------------------------------- /sp-sublimetext-like.el: -------------------------------------------------------------------------------- 1 | ;;; sp-sublimetext-like.el --- Behavior for inserting parentheses similar to SublimeText editor. -*- lexical-binding: t; -*- 2 | ;; 3 | ;; Author: Konstantin Kharlamov 4 | ;; Maintainer: Matus Goljer 5 | ;; Created: 16 December 2020 6 | ;; Keywords: convenience editing 7 | ;; URL: https://github.com/Fuco1/smartparens 8 | ;; 9 | ;; This file is not part of GNU Emacs. 10 | ;; 11 | ;;; License: 12 | ;; 13 | ;; This file is part of Smartparens. 14 | ;; 15 | ;; Smartparens is free software; you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | ;; 20 | ;; Smartparens is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | ;; 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Smartparens. If not, see . 27 | ;; 28 | ;;; Commentary: 29 | ;; 30 | ;; This file configuation to make smartparens insertion behavae similarly to 31 | ;; SublimeText editor. To use it, simply add: 32 | ;; 33 | ;; (require 'sp-sublimetext-like) 34 | ;; 35 | ;; into your configuration. You can use this in conjunction with the 36 | ;; default config or your own configuration. 37 | ;; 38 | ;;; Code: 39 | 40 | (require 'smartparens) 41 | 42 | (defun sp-point-not-before-word (_ action __) 43 | "In insert and autoskip actions returns t when next symbol is 44 | not a word constituent." 45 | (if (memq action '(insert autoskip)) 46 | (looking-at "\\(\\Sw\\|$\\)") 47 | t)) 48 | 49 | (let ((when '(sp-point-not-before-word)) 50 | (actions '(insert wrap autoskip navigate))) 51 | (sp-pair "{" "}" :when when :actions actions) 52 | (sp-pair "[" "]" :when when :actions actions) 53 | (sp-pair "(" ")" :when when :actions actions)) 54 | 55 | (provide 'sp-sublimetext-like) 56 | 57 | ;;; sp-sublimetext-like.el ends here 58 | -------------------------------------------------------------------------------- /smartparens-coq.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-coq.el --- Additional configuration for Coq proof assistant -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2024 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 29 June 2024 8 | ;; Keywords: smartparens, coq 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Coq proof 33 | ;; assistant. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-coq) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (sp-with-modes '(coq-mode) 51 | ;; Disable ' because it is used in pattern-matching 52 | (sp-local-pair "'" nil :actions nil) 53 | ;; Disable ` because it is used in polymorphic variants 54 | (sp-local-pair "`" nil :actions nil) 55 | (sp-local-pair "(*" "*)" 56 | :post-handlers '(("| " "SPC") 57 | (" | " "*")))) 58 | 59 | (provide 'smartparens-coq) 60 | ;;; smartparens-coq.el ends here 61 | -------------------------------------------------------------------------------- /smartparens-text.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-text.el --- Additional configuration for text-mode. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2018 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 16 July 2017 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for `text-mode'. 33 | ;; To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-text) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (defun sp-text-mode-emoticon-p (_id action _context) 51 | (when (memq action '(insert navigate)) 52 | (sp--looking-back-p ":-?[()]" 3))) 53 | 54 | (defun sp-text-mode-skip-emoticon (ms mb _me) 55 | (when (member ms '("(" ")")) 56 | (save-excursion 57 | (goto-char mb) 58 | (sp--looking-back-p ":-?" 2)))) 59 | 60 | (sp-local-pair 'text-mode "(" nil 61 | :unless '(:add sp-text-mode-emoticon-p) 62 | :skip-match 'sp-text-mode-skip-emoticon) 63 | 64 | (provide 'smartparens-text) 65 | ;;; smartparens-text.el ends here 66 | -------------------------------------------------------------------------------- /test/smartparens-scala-test.el: -------------------------------------------------------------------------------- 1 | (require 'scala-mode) 2 | (require 'smartparens-scala) 3 | 4 | (ert-deftest sp-test-scala-bracket () 5 | "Close a normal bracket" 6 | (sp-test-with-temp-buffer "def foo|" 7 | (scala-mode) 8 | (execute-kbd-macro "(bar: String") 9 | (should (equal (buffer-string) "def foo(bar: String)")))) 10 | 11 | (ert-deftest sp-test-scala-bracket-space () 12 | "Close a normal bracket with padding on SPACE." 13 | (sp-test-with-temp-buffer "foo.map|" 14 | (scala-mode) 15 | (execute-kbd-macro "( _.toString") 16 | (should (equal (buffer-string) "foo.map( _.toString )")))) 17 | 18 | (ert-deftest sp-test-scala-curly () 19 | "Close a curly bracket" 20 | (sp-test-with-temp-buffer "foo.map|" 21 | (scala-mode) 22 | (execute-kbd-macro "{f => f.toString") 23 | (should (equal (buffer-string) "foo.map{f => f.toString}")))) 24 | 25 | (ert-deftest sp-test-scala-curly-space () 26 | "Close a curly bracket with padding on SPACE" 27 | (sp-test-with-temp-buffer "foo.map |" 28 | ;; it might be nice in a future update to not need the prefix space 29 | (scala-mode) 30 | (execute-kbd-macro "{ f => f.toString") 31 | (should (equal (buffer-string) "foo.map { f => f.toString }")))) 32 | 33 | (ert-deftest sp-test-scala-curly-newline () 34 | "Close a curly bracket with an indented block on newline" 35 | (sp-test-with-temp-buffer "foo.map |" 36 | (scala-mode) 37 | (execute-kbd-macro (kbd "{ RET f SPC => SPC f.toString")) 38 | (sp-buffer-equals "foo.map {\n f => f.toString|\n}"))) 39 | 40 | (ert-deftest sp-test-scala-curly-wrap () 41 | "Wrap a region in an indented block" 42 | (sp-test-with-temp-buffer "|fooM" 43 | (scala-mode) 44 | (execute-kbd-macro "{") 45 | (should (equal (buffer-string) "{\n foo\n}")))) 46 | 47 | (ert-deftest sp-test-scala-curly-wrap-indent () 48 | "Wrap an indented region in an indented block" 49 | (sp-test-with-temp-buffer "if (true)\n |fooM" 50 | (scala-mode) 51 | (execute-kbd-macro "{") 52 | (should (equal (buffer-string) "if (true)\n{\n foo\n}")))) 53 | 54 | (ert-deftest sp-test-scala-triple-quotes () 55 | "Close triple quotes" 56 | (sp-test-with-temp-buffer "sql|" 57 | (scala-mode) 58 | (execute-kbd-macro (kbd "\"\"\"SELECT")) 59 | (should (equal (buffer-string) "sql\"\"\"SELECT\"\"\"")))) 60 | -------------------------------------------------------------------------------- /smartparens-c.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-c.el --- Additional configuration for C/C++ mode. -*- lexical-binding: t; -*- 2 | ;; 3 | ;; Copyright (C) 2019-2020, 2022 Naoya Yamashita, Matus Goljer 4 | ;; 5 | ;; Author: Naoya Yamashita 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 23 June 2019 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | ;; 11 | ;; This file is not part of GNU Emacs. 12 | ;; 13 | ;;; License: 14 | ;; 15 | ;; This file is part of Smartparens. 16 | ;; 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | ;; 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | ;; 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | ;; 30 | ;;; Commentary: 31 | ;; 32 | ;; This file provides some additional configuration for C/C++ mode. 33 | ;; To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-c) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;;; Code: 41 | 42 | (require 'smartparens) 43 | 44 | ;; remap electric delete functions to smartparens function 45 | (define-key smartparens-strict-mode-map [remap c-electric-delete-forward] 'sp-delete-char) 46 | (define-key smartparens-strict-mode-map [remap c-electric-backspace] 'sp-backward-delete-char) 47 | 48 | (sp-with-modes sp-c-modes 49 | (sp-local-pair "{" nil :post-handlers '(("||\n[i]" "RET"))) 50 | (sp-local-pair "/*" "*/" :post-handlers '(("| " "SPC") 51 | ("* ||\n[i]" "RET")))) 52 | 53 | ;; inline formulas for doxygen 54 | (sp-with-modes sp-c-modes 55 | (sp-local-pair "\\f[" "\\f]" :when '(sp-in-comment-p)) 56 | (sp-local-pair "\\f$" "\\f$" :when '(sp-in-comment-p))) 57 | 58 | (provide 'smartparens-c) 59 | ;;; smartparens-c.el ends here 60 | -------------------------------------------------------------------------------- /test/smartparens-evil-test.el: -------------------------------------------------------------------------------- 1 | (require 'evil) 2 | 3 | (ert-deftest sp-test-evil-enabled-copy-sexp () 4 | "When `evil-mode' is enabled, copying sexp copies to 0 register." 5 | (sp-test-with-temp-elisp-buffer "|(a b c)" 6 | (evil-set-register ?0 nil) 7 | (evil-mode) 8 | (sp-kill-sexp 1 t) 9 | (evil-mode -1) 10 | (should (equal (buffer-string) (evil-get-register ?0 'no-error))))) 11 | 12 | (ert-deftest sp-test-evil-disabled-copy-sexp () 13 | "When `evil-mode' is disabled, copying sexp doesn't modify 0 register." 14 | (sp-test-with-temp-elisp-buffer "|(a b c)" 15 | (evil-set-register ?0 nil) 16 | (evil-mode -1) 17 | (sp-kill-sexp 1 t) 18 | (should (not (equal (buffer-string) (evil-get-register ?0 'no-error)))))) 19 | 20 | (ert-deftest sp-test-evil-enabled-copy-sexp-with-register () 21 | "When `evil-mode' is enabled, copying a sexp with register set will 22 | copy the sexp into that register." 23 | (sp-test-with-temp-elisp-buffer "|(a b c)" 24 | (evil-mode) 25 | (setq evil-this-register ?a) 26 | (sp-kill-sexp 1 t) 27 | (evil-mode -1) 28 | (should (equal (buffer-string) (evil-get-register ?a 'no-error))))) 29 | 30 | (ert-deftest sp-test-evil-disabled-copy-sexp-with-register () 31 | "When `evil-mode' is disabled, copying a sexp with register set will not 32 | copy the sexp into that register." 33 | (sp-test-with-temp-elisp-buffer "|(a b c)" 34 | (evil-mode -1) 35 | (setq evil-this-register ?c) 36 | (sp-kill-sexp 1 t) 37 | (should (not (equal (buffer-string) (evil-get-register ?c 'no-error)))))) 38 | 39 | (ert-deftest sp-test-evil-enabled-kill-sexp-with-register () 40 | "When `evil-mode' is enabled, killing a sexp with register set will 41 | copy the sexp into that register." 42 | (sp-test-with-temp-elisp-buffer "|(a b c)" 43 | (evil-mode) 44 | (setq evil-this-register ?b) 45 | (sp-kill-sexp 1 nil) 46 | (evil-mode -1) 47 | (should (equal "(a b c)" (evil-get-register ?b 'no-error))))) 48 | 49 | (ert-deftest sp-test-evil-disabled-kill-sexp-with-register () 50 | "When `evil-mode' is disabled, killing a sexp with register set will not 51 | copy the sexp into that register." 52 | (sp-test-with-temp-elisp-buffer "|(a b c)" 53 | (evil-mode -1) 54 | (setq evil-this-register ?d) 55 | (sp-kill-sexp 1 nil) 56 | (should (not (equal "(a b c)" (evil-get-register ?d 'no-error)))))) 57 | -------------------------------------------------------------------------------- /smartparens-clojure.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-clojure.el --- Additional configuration for Clojure mode. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2016, 2018-2019 Vitalie Spinu, Matus Goljer 4 | 5 | ;; Author: Vitalie Spinu 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 14 July 2016 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | ;; 11 | ;; This file is not part of GNU Emacs. 12 | ;; 13 | ;;; License: 14 | ;; 15 | ;; This file is part of Smartparens. 16 | ;; 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | ;; 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | ;; 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | ;; 30 | ;;; Commentary: 31 | ;; 32 | ;; This file provides some additional configuration for Clojure mode. To use 33 | ;; it, simply add: 34 | ;; 35 | ;; (require 'smartparens-clojure) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;;; Code: 41 | 42 | (require 'smartparens) 43 | 44 | (defvar sp-clojure-prefix "\\(?:[@`'#~,_?^]+\\)" 45 | "Prefix used in `sp-sexp-prefix' for clojure modes.") 46 | 47 | (dolist (mode '( 48 | cider-repl-mode 49 | clojure-mode 50 | clojure-ts-mode 51 | clojurec-mode 52 | clojurec-ts-mode 53 | clojurescript-mode 54 | clojurescript-ts-mode 55 | )) 56 | (add-to-list 'sp-sexp-prefix `(,mode regexp ,sp-clojure-prefix))) 57 | 58 | ;; Match "`" with "`" in strings and comments 59 | (sp-with-modes sp-clojure-modes 60 | (sp-local-pair "`" "`" 61 | :when '(sp-in-string-p 62 | sp-in-comment-p) 63 | :unless '(sp-lisp-invalid-hyperlink-p))) 64 | 65 | (provide 'smartparens-clojure) 66 | ;;; smartparens-clojure.el ends here 67 | -------------------------------------------------------------------------------- /smartparens-rst.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-rst.el --- Additional configuration for rst based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2019-2020 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 28th January 2019 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for rst based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-rst) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | (require 'smartparens-text) 50 | (require 'smartparens-markdown) 51 | 52 | (defun sp-rst-point-after-backtick (_id action _context) 53 | (when (eq action 'insert) 54 | (sp--looking-back-p "`_"))) 55 | 56 | (sp-with-modes 'rst-mode 57 | (sp-local-pair "*" "*" 58 | :unless '(sp--gfm-point-after-word-p sp-point-at-bol-p) 59 | :post-handlers '(("[d1]" "SPC")) 60 | :skip-match 'sp--gfm-skip-asterisk) 61 | (sp-local-pair "**" "**") 62 | (sp-local-pair "_" "_" :unless '(sp-point-after-word-p sp-rst-point-after-backtick)) 63 | (sp-local-pair "``" "``")) 64 | 65 | (provide 'smartparens-rst) 66 | ;;; smartparens-rst.el ends here 67 | -------------------------------------------------------------------------------- /test/smartparens-get-paired-expression-ruby-test.el: -------------------------------------------------------------------------------- 1 | (defun sp-test--paired-expression-parse-in-ruby (initial result &optional back) 2 | (let ((sp-pairs '((t . ((:open "def" :close "end" :actions (insert wrap autoskip navigate)) 3 | (:open "if" :close "end" :actions (insert wrap autoskip navigate)) 4 | (:open "do" :close "end" :actions (insert wrap autoskip navigate)) 5 | (:open "begin" :close "end" :actions (insert wrap autoskip navigate)) 6 | (:open "(" :close ")" :actions (insert wrap autoskip navigate))))))) 7 | (sp-test-with-temp-buffer initial 8 | (ruby-mode) 9 | (should (equal (sp-get-paired-expression back) result))))) 10 | 11 | (ert-deftest sp-test-get-paired-expression-ruby () 12 | (sp-test--paired-expression-parse-in-ruby "|begin end" '(:beg 1 :end 10 :op "begin" :cl "end" :prefix "" :suffix "")) 13 | (sp-test--paired-expression-parse-in-ruby "begin |end" '(:beg 1 :end 10 :op "begin" :cl "end" :prefix "" :suffix "")) 14 | (sp-test--paired-expression-parse-in-ruby "|def foo bar if blaz end end" '(:beg 1 :end 28 :op "def" :cl "end" :prefix "" :suffix "")) 15 | (sp-test--paired-expression-parse-in-ruby "|def foo end;" '(:beg 1 :end 12 :op "def" :cl "end" :prefix "" :suffix "")) 16 | ) 17 | 18 | (ert-deftest sp-test-get-paired-expression-ruby-backward () 19 | (sp-test--paired-expression-parse-in-ruby "begin end|" '(:beg 1 :end 10 :op "begin" :cl "end" :prefix "" :suffix "") t) 20 | (sp-test--paired-expression-parse-in-ruby "begin| end" '(:beg 1 :end 10 :op "begin" :cl "end" :prefix "" :suffix "") t) 21 | (sp-test--paired-expression-parse-in-ruby "def foo bar if blaz end end|" '(:beg 1 :end 28 :op "def" :cl "end" :prefix "" :suffix "") t) 22 | (sp-test--paired-expression-parse-in-ruby "def foo end;|" '(:beg 1 :end 12 :op "def" :cl "end" :prefix "" :suffix "") t) 23 | (sp-test--paired-expression-parse-in-ruby "asd (asd)|#asdas" '(:beg 5 :end 10 :op "(" :cl ")" :prefix "" :suffix "") t) 24 | (sp-test--paired-expression-parse-in-ruby "C = %w(asd)|#asdas" '(:beg 7 :end 12 :op "(" :cl ")" :prefix "" :suffix "") t) 25 | ) 26 | 27 | (ert-deftest sp-test-get-paired-expression-ruby-fail () 28 | (sp-test--paired-expression-parse-in-ruby "|def en" nil) 29 | (sp-test--paired-expression-parse-in-ruby "|do do end do" nil) 30 | ) 31 | 32 | (ert-deftest sp-test-get-paired-expression-ruby-backward-fail () 33 | (sp-test--paired-expression-parse-in-ruby "de end|" nil t) 34 | ) 35 | -------------------------------------------------------------------------------- /test/smartparens-insertion-specification-parser-test.el: -------------------------------------------------------------------------------- 1 | ;; TODO: separate into separate tests for each invocation -> easier 2 | ;; debugging 3 | (ert-deftest sp-test-insertion-specification-parser () 4 | (should (equal (sp--parse-insertion-spec "ab") 5 | '(progn (insert "ab")))) 6 | (should (equal (sp--parse-insertion-spec "a|b") 7 | '(progn 8 | (insert "a") 9 | (save-excursion 10 | (insert "b"))))) 11 | (should (equal (sp--parse-insertion-spec "a\\|b") 12 | '(progn (insert "a|") (insert "b")))) 13 | (should (equal (sp--parse-insertion-spec "a\\||b") 14 | '(progn 15 | (insert "a|") 16 | (save-excursion 17 | (insert "b"))))) 18 | (should (equal (sp--parse-insertion-spec "a\\[b]") 19 | '(progn (insert "a[") (insert "b]")))) 20 | (should (equal (sp--parse-insertion-spec "a\\[b[i]") 21 | '(progn 22 | (insert "a[") 23 | (insert "b") 24 | (indent-according-to-mode)))) 25 | (should (equal (sp--parse-insertion-spec "a||b") 26 | '(progn 27 | (insert "a") 28 | (save-excursion 29 | (insert "b")) 30 | (indent-according-to-mode)))) 31 | (should (equal (sp--parse-insertion-spec "a|[i]b") 32 | '(progn 33 | (insert "a") 34 | (save-excursion 35 | (indent-according-to-mode) 36 | (insert "b"))))) 37 | (should (equal (sp--parse-insertion-spec "a|b[i]") 38 | '(progn 39 | (insert "a") 40 | (save-excursion 41 | (insert "b") 42 | (indent-according-to-mode))))) 43 | (should (equal (sp--parse-insertion-spec "[i]a|b") 44 | '(progn 45 | (indent-according-to-mode) 46 | (insert "a") 47 | (save-excursion 48 | (insert "b"))))) 49 | (should (equal (sp--parse-insertion-spec "[i]") 50 | '(progn 51 | (indent-according-to-mode)))) 52 | (should (equal (sp--parse-insertion-spec "[d3]") 53 | '(progn 54 | (delete-char 3)))) 55 | (should (equal (sp--parse-insertion-spec "[d12]") 56 | '(progn 57 | (delete-char 12))))) 58 | -------------------------------------------------------------------------------- /dev/_old/talk.org: -------------------------------------------------------------------------------- 1 | * Intro 2 | 3 | smartparens.el 4 | wrap-region.el 5 | textmate.el 6 | autopair.el 7 | paredit.el 8 | 9 | why - to give user more freedome 10 | 11 | * Defining pairs 12 | ** basic pairs present everywhere 13 | ** more elaborate pairs 14 | 15 | ("\\\\\\\\(" . "\\\\\\\\)") ;; emacs regexp parens 16 | ("\\{" . "\\}") 17 | ("\\\\(" . "\\\\)") 18 | ("\\\"" . "\\\"") 19 | ("/*" . "*/") 20 | ("\"" . "\"") 21 | ("'" . "'") 22 | ("(" . ")") 23 | ("[" . "]") 24 | ("{" . "}") 25 | ("`" . "'") ;; tap twice for tex double quotes 26 | 27 | * Auto insertion 28 | ** Global pairs 29 | ** something about permissions (briefly) 30 | 31 | 3 layers/4 levels 32 | 33 | ** defining pairs 34 | (sp-add-pair "$" "$") 35 | 36 | *** locally 37 | (sp-add-local-pair "`" "`" 'markdown-mode) 38 | 39 | - used to override global definitions. 40 | 41 | ** smart handling of closing pairs. 42 | 43 | if typed in, it is skipped. 44 | 45 | ** automatic deletion of the whole pair 46 | 47 | \{|\} < | 48 | \{\} < \{ 49 | 50 | * Wrapping 51 | ** regular 52 | just with normally defined pairs () [] {} "" \{\} \\(\\) 53 | 54 | ** "tags" 55 | (sp-add-tag-pair "<" "<_>" "" 'sp-match-sgml-tags '(html-mode sgml-mode)) 56 | (sp-add-tag-pair "\\b" "\\begin{_}" "\\end{_}" 'identity '(latex-mode tex-mode)) 57 | (sp-add-tag-pair "2" "**" "**" nil '(markdown-mode)) 58 | 59 | 60 | - nil = default to identity... 61 | 62 | ** html-mode 63 |
    64 |
  • banana
  • 65 |
  • banana
  • 66 |
  • banana
  • 67 |
68 | 69 | ** latex-mode 70 | \begin{itemize} 71 | \item Shetland 72 | \item Welsh 73 | \item Australian 74 | \end{itemize} 75 | 76 | * Navigation 77 | 78 | ** forward-sexp 79 | backward-sexp -- s-expression 80 | 81 | (define-key sp-keymap (kbd "C-M-f") 'sp-forward-sexp) 82 | (define-key sp-keymap (kbd "C-M-b") 'sp-backward-sexp) 83 | 84 | ** down-list 85 | 86 | (define-key sp-keymap (kbd "C-M-d") 'sp-down-sexp) 87 | (define-key sp-keymap (kbd "C-M-a") 'sp-backward-down-sexp) 88 | 89 | ** up-list 90 | up-backward-list 91 | 92 | (define-key sp-keymap (kbd "C-M-e") 'sp-up-sexp) 93 | (define-key sp-keymap (kbd "C-M-u") 'sp-backward-up-sexp) 94 | 95 | ** next-list 96 | previous-list 97 | 98 | (define-key sp-keymap (kbd "C-M-n") 'sp-next-sexp) 99 | (define-key sp-keymap (kbd "C-M-p") 'sp-previous-sexp) 100 | 101 | ** kill-sexp 102 | 103 | (define-key sp-keymap (kbd "C-M-k") 'sp-kill-sexp) 104 | -------------------------------------------------------------------------------- /test/smartparens-get-comment-bounds-test.el: -------------------------------------------------------------------------------- 1 | ;; #399 2 | (ert-deftest sp-test-get-comment-bounds-c () 3 | (sp-test-with-temp-buffer 4 | "int foo; /* foo|bar */" 5 | (progn 6 | (c++-mode) 7 | ;; because emacs doesn't return proper info on the very first 8 | ;; call of syntax-ppss, we must call it before we do actual 9 | ;; parsing .____________. 10 | (save-excursion (syntax-ppss 1))) 11 | (should (equal (sp-get-comment-bounds) '(10 . 22)))) 12 | (sp-test-with-temp-buffer 13 | "int foo; |/* foobar */" 14 | (progn 15 | (c++-mode) 16 | ;; because emacs doesn't return proper info on the very first 17 | ;; call of syntax-ppss, we must call it before we do actual 18 | ;; parsing .____________. 19 | (save-excursion (syntax-ppss 1))) 20 | (should (equal (sp-get-comment-bounds) '(10 . 22)))) 21 | (sp-test-with-temp-buffer 22 | "int foo; // foo|bar" 23 | (progn 24 | (c++-mode) 25 | (save-excursion (syntax-ppss 1))) 26 | (should (equal (sp-get-comment-bounds) '(10 . 19))))) 27 | 28 | (ert-deftest sp-test-get-comment-bounds-elisp () 29 | (sp-test-with-temp-elisp-buffer 30 | "(foo bar) ;; foo| bar" 31 | (should (equal (sp-get-comment-bounds) '(13 . 23))) 32 | ) 33 | (sp-test-with-temp-elisp-buffer 34 | "(foo bar) 35 | ;; foo| bar 36 | ;; foo bar 37 | (bar)" 38 | (should (equal (sp-get-comment-bounds) '(11 . 40)))) 39 | (sp-test-with-temp-elisp-buffer 40 | "(foo bar) 41 | ;; foo bar 42 | ;; foo| bar 43 | (bar)" 44 | (should (equal (sp-get-comment-bounds) '(11 . 40))))) 45 | 46 | (ert-deftest sp-test-get-comment-bounds-elisp-with-comment-starting-at-bobp () 47 | (sp-test-with-temp-elisp-buffer ";; |foobar" 48 | (should (equal (sp-get-comment-bounds) '(1 . 10))))) 49 | 50 | (ert-deftest sp-test-get-comment-bounds-pascal () 51 | (sp-test-with-temp-buffer 52 | "var foo:integer; (* foo|bar *)" 53 | (progn 54 | (pascal-mode) 55 | (save-excursion (syntax-ppss 1))) 56 | (should (equal (sp-get-comment-bounds) '(18 . 30)))) 57 | (sp-test-with-temp-buffer 58 | "var foo:integer; { foo|bar }" 59 | (progn 60 | (pascal-mode) 61 | (save-excursion (syntax-ppss 1))) 62 | (should (equal (sp-get-comment-bounds) '(18 . 28))))) 63 | 64 | (ert-deftest sp-test-get-comment-bounds-pascal-with-comment-starting-at-bobp () 65 | (sp-test-with-temp-buffer "(* foo|bar *)" 66 | (progn 67 | (pascal-mode) 68 | (save-excursion (syntax-ppss 1))) 69 | (should (equal (sp-get-comment-bounds) '(1 . 13))))) 70 | -------------------------------------------------------------------------------- /test/smartparens-movement-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | 3 | (ert-deftest sp-test-next-sexp () 4 | (sp-test-with-temp-elisp-buffer "|(foo) (bar)" 5 | (call-interactively 'sp-next-sexp) 6 | (sp-buffer-equals "(foo) |(bar)")) 7 | 8 | (sp-test-with-temp-elisp-buffer "(f|oo bar)" 9 | (call-interactively 'sp-next-sexp) 10 | (sp-buffer-equals "(|foo bar)")) 11 | 12 | (sp-test-with-temp-elisp-buffer "(f|oo bar)" 13 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 14 | (call-interactively 'sp-next-sexp) 15 | (sp-buffer-equals "(foo |bar)")) 16 | 17 | (sp-test-with-temp-elisp-buffer "(foo) |(bar)" 18 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 19 | (call-interactively 'sp-next-sexp) 20 | (sp-buffer-equals "(foo) |(bar)")) 21 | 22 | (sp-test-with-temp-elisp-buffer "((fo|o) (bar))" 23 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 24 | (call-interactively 'sp-next-sexp) 25 | (sp-buffer-equals "((foo) |(bar))")) 26 | 27 | (sp-test-with-temp-elisp-buffer "(((f|oo))) bar" 28 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 29 | (call-interactively 'sp-next-sexp) 30 | (sp-buffer-equals "(((foo))) |bar"))) 31 | 32 | (ert-deftest sp-test-next-sexp-jump-up () 33 | "`sp-next-sexp' should jump up a level when 34 | there are no more expressions at the current level." 35 | (sp-test-with-temp-elisp-buffer "(foo|) (bar)" 36 | (call-interactively 'sp-next-sexp) 37 | (sp-buffer-equals "|(foo) (bar)"))) 38 | 39 | (ert-deftest sp-test-previous-sexp () 40 | "Basic test of `sp-previous-sexp'." 41 | (sp-test-with-temp-elisp-buffer "((foo) bar| (baz quux))" 42 | (call-interactively 'sp-previous-sexp) 43 | (sp-buffer-equals "((foo)| bar (baz quux))")) 44 | 45 | (sp-test-with-temp-elisp-buffer "((foo)| bar (baz quux))" 46 | (call-interactively 'sp-previous-sexp) 47 | (sp-buffer-equals "((foo) bar (baz quux))|")) 48 | 49 | (sp-test-with-temp-elisp-buffer "(foo b|ar baz)" 50 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 51 | (call-interactively 'sp-previous-sexp) 52 | (sp-buffer-equals "(foo| bar baz)")) 53 | 54 | (sp-test-with-temp-elisp-buffer "(f|oo bar baz)" 55 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 56 | (call-interactively 'sp-previous-sexp) 57 | (sp-buffer-equals "(foo bar baz)|")) 58 | 59 | (sp-test-with-temp-elisp-buffer "(foo (b|ar baz))" 60 | (set (make-local-variable 'sp-navigate-interactive-always-progress-point) t) 61 | (call-interactively 'sp-previous-sexp) 62 | (sp-buffer-equals "(foo| (bar baz))"))) 63 | -------------------------------------------------------------------------------- /dev/_old/smartparens.org: -------------------------------------------------------------------------------- 1 | Dev notes :P 2 | 3 | All functions are in global mode by default. That means they work in any mode. Each function can be turned off globally or for specific modes and also only turned on for specific modes. That means, there will be black-lists and allow-lists. The order of evaluation is: 4 | 5 | 1. global allow - function enabled everywhere (default) 6 | 2. local ban - function disabled in specific modes 7 | 3. global ban - function disabled everywhere 8 | 4. local allow - function enabled in specific modes. If a function is in this list, it is automatically globally banned 9 | 10 | Structure of local lists is ((command . (modes...))...) 11 | Structure of global list is (command...) 12 | 13 | * customize/mode stuff 14 | - [X] added as mode and globalized mode 15 | 16 | * auto-pair 17 | ** when pair character/string is inserted, insert the closing pair, place cursor inside 18 | - [X] For example, on (, insert ). On \{, insert \}, on ", insert closing ". If typopunct is enabled, replace quotes with "typo quotes". This should be somehow provided by typopunct package, but if not possible, we should reimplement it ourselves. 19 | - [ ] There can be a special treatment, for example after {, if followed by place the ending } with a new line inbetween. 20 | - [X] If user types the closing pair, it should skip the auto-inserted one 21 | - [X] When the pair is empty and the point is inside -- (|), on backspace the whole pair should be deleted. If the pair is multi-character and the point is after the closing pair, it should be deleted as a whole. For example: /* */| after backspace should be /* | 22 | - [ ] Since we remap all the trigger keys to self-insert, some behaviour might be lost (c-electric or other auto-indentation hackery). We should add some support for defining special behaviours for these events (similar to point 2) 23 | ** when a region is active, wrap it with the char/pair/string 24 | - [ ] If we have an active region, instead of inserting the pair, we wrap the region in the pair. 25 | - [ ] There should also be an unwrap command. If we're at the of a "pair-wrapped region", after running the command, it should unwrap. 26 | 27 | * Escape quotes within strings 28 | - [X] When typing " inside a string, automatically escape it with \. 29 | - [ ] When wrapping a region with " (or other "quote" character), automatically escape included quotes. Do not double-escape quotes! (that is, already escaped quotes are not escaped again) 30 | - [ ] When wrapping inside a quoted region, autoescape quotes. (do we need to define what a quote is?) 31 | - [X] Pair deletion should also work inside quoted strings. 32 | 33 | 34 | Each pair is uniquely determined by the open bracket (so it will be used as an "ID" for the pair) 35 | Pair format: 36 | - Open bracket (=id) 37 | - Close bracket 38 | - (optional) trigger for wrapping with this pair 39 | -------------------------------------------------------------------------------- /smartparens-javascript.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-javascript.el --- Additional configuration for JavaScript based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2017-2019 Marinin Tim 4 | ;; Author: Tim Marinin 5 | ;; Maintainer: Tim Marinin 6 | ;; Created: 2017-03-03 7 | ;; Keywords: abbrev convenience editing javascript 8 | ;; URL: https://github.com/Fuco1/smartparens 9 | 10 | ;; This file is not part of GNU Emacs. 11 | 12 | ;;; License: 13 | 14 | ;; This file is part of Smartparens. 15 | 16 | ;; Smartparens is free software; you can redistribute it and/or modify 17 | ;; it under the terms of the GNU General Public License as published by 18 | ;; the Free Software Foundation, either version 3 of the License, or 19 | ;; (at your option) any later version. 20 | 21 | ;; Smartparens is distributed in the hope that it will be useful, 22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | ;; GNU General Public License for more details. 25 | 26 | ;; You should have received a copy of the GNU General Public License 27 | ;; along with Smartparens. If not, see . 28 | 29 | ;;; Commentary: 30 | 31 | ;; This file provides some additional configuration for JavaScript based 32 | ;; modes. To use it, simply add: 33 | ;; 34 | ;; (require 'smartparens-javascript) 35 | ;; 36 | ;; into your configuration. You can use this in conjunction with the 37 | ;; default config or your own configuration. 38 | ;; 39 | ;; If you have good ideas about what should be added please file an 40 | ;; issue on the github tracker. 41 | ;; 42 | ;; For more info, see github readme at 43 | ;; https://github.com/Fuco1/smartparens 44 | 45 | ;;; Code: 46 | 47 | (require 'smartparens) 48 | 49 | (defvar sp--javascript-modes '( 50 | js-mode 51 | javascript-mode 52 | js2-mode 53 | typescript-mode 54 | rjsx-mode 55 | js-ts-mode 56 | typescript-ts-mode 57 | tsx-ts-mode 58 | ) 59 | "List of JavaScript modes.") 60 | 61 | ;; (|sys).path.append---the dot should not travel with the closing 62 | ;; paren 63 | (--each sp--javascript-modes 64 | (add-to-list 'sp-sexp-suffix (list it 'regexp ""))) 65 | 66 | (defun sp-javascript-skip-match-angle-bracket (ms mb _me) 67 | "Non-nil if we should ignore the bracket as valid delimiter." 68 | (and (string= ms ">") (= (char-before mb) ?=))) 69 | 70 | (sp-with-modes sp--javascript-modes 71 | (sp-local-pair "<" ">" 72 | :skip-match 'sp-javascript-skip-match-angle-bracket)) 73 | 74 | (provide 'smartparens-javascript) 75 | ;;; smartparens-javascript.el ends here 76 | -------------------------------------------------------------------------------- /test/smartparens-get-paired-expression-latex-test.el: -------------------------------------------------------------------------------- 1 | (defun sp-test--paired-expression-parse-in-latex (initial result &optional back) 2 | (let ((sp-pairs '((t . ((:open "\\{" :close "\\}" :actions (insert wrap autoskip navigate)) 3 | (:open "(" :close ")" :actions (insert wrap autoskip navigate)) 4 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)) 5 | (:open "{" :close "}" :actions (insert wrap autoskip navigate)) 6 | (:open "\"" :close "\"" :actions (insert wrap autoskip navigate)) 7 | (:open "\\\"" :close "\\\"" :actions (insert wrap autoskip navigate)) 8 | (:open "\\langle" :close "\\rangle" :actions (insert wrap autoskip navigate)) 9 | (:open "OPEN" :close "CLOSE" :actions (insert wrap autoskip navigate)) 10 | (:open "\\big(" :close "\\big)" :actions (insert wrap autoskip navigate) :trigger "\\b") 11 | (:open "``" :close "''" :actions (insert wrap autoskip navigate)) 12 | (:open "`" :close "'" :actions (insert wrap autoskip navigate)) 13 | (:open "$" :close "$" :actions (insert wrap autoskip navigate))))))) 14 | (sp-test-with-temp-buffer initial 15 | (latex-mode) 16 | (should (equal (sp-get-paired-expression back) result))))) 17 | 18 | (ert-deftest sp-test-get-paired-expression-latex () 19 | (sp-test--paired-expression-parse-in-latex "|``''" '(:beg 1 :end 5 :op "``" :cl "''" :prefix "" :suffix "")) 20 | (sp-test--paired-expression-parse-in-latex "``|''" '(:beg 1 :end 5 :op "``" :cl "''" :prefix "" :suffix "")) 21 | (sp-test--paired-expression-parse-in-latex "|foo ``bar'' baz" '(:beg 5 :end 12 :op "``" :cl "''" :prefix "" :suffix "")) 22 | (sp-test--paired-expression-parse-in-latex "|`'" '(:beg 1 :end 3 :op "`" :cl "'" :prefix "" :suffix "")) 23 | (sp-test--paired-expression-parse-in-latex "`|'" '(:beg 1 :end 3 :op "`" :cl "'" :prefix "" :suffix "")) 24 | (sp-test--paired-expression-parse-in-latex "|foo `bar' baz" '(:beg 5 :end 10 :op "`" :cl "'" :prefix "" :suffix "")) 25 | ) 26 | 27 | (ert-deftest sp-test-get-paired-expression-latex-backward () 28 | (sp-test--paired-expression-parse-in-latex "``''|" '(:beg 1 :end 5 :op "``" :cl "''" :prefix "" :suffix "") t) 29 | (sp-test--paired-expression-parse-in-latex "``|''" '(:beg 1 :end 5 :op "``" :cl "''" :prefix "" :suffix "") t) 30 | (sp-test--paired-expression-parse-in-latex "foo ``bar'' b|az" '(:beg 5 :end 12 :op "``" :cl "''" :prefix "" :suffix "") t) 31 | (sp-test--paired-expression-parse-in-latex "`'|" '(:beg 1 :end 3 :op "`" :cl "'" :prefix "" :suffix "") t) 32 | (sp-test--paired-expression-parse-in-latex "`|'" '(:beg 1 :end 3 :op "`" :cl "'" :prefix "" :suffix "") t) 33 | (sp-test--paired-expression-parse-in-latex "foo `bar' baz|" '(:beg 5 :end 10 :op "`" :cl "'" :prefix "" :suffix "") t) 34 | ) 35 | -------------------------------------------------------------------------------- /smartparens-ml.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-ml.el --- Additional configuration for ML languages -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2016-2019 Ta Quang Trung 4 | ;; Copyright (C) 2017, 2022 Matus Goljer 5 | 6 | ;; Author: Ta Quang Trung 7 | ;; Matus Goljer 8 | ;; Louis Roché 9 | ;; Maintainer: Matus Goljer 10 | ;; Created: 14 July 2016 11 | ;; Keywords: smartparens, ML, ocaml, reason 12 | ;; URL: https://github.com/Fuco1/smartparens 13 | 14 | ;; This file is not part of GNU Emacs. 15 | 16 | ;;; License: 17 | 18 | ;; This file is part of Smartparens. 19 | 20 | ;; Smartparens is free software; you can redistribute it and/or modify 21 | ;; it under the terms of the GNU General Public License as published by 22 | ;; the Free Software Foundation, either version 3 of the License, or 23 | ;; (at your option) any later version. 24 | 25 | ;; Smartparens is distributed in the hope that it will be useful, 26 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | ;; GNU General Public License for more details. 29 | 30 | ;; You should have received a copy of the GNU General Public License 31 | ;; along with Smartparens. If not, see . 32 | 33 | ;;; Commentary: 34 | 35 | ;; This file provides some additional configuration for ML languages. 36 | ;; To use it, simply add: 37 | ;; 38 | ;; (require 'smartparens-ml) 39 | ;; 40 | ;; into your configuration. You can use this in conjunction with the 41 | ;; default config or your own configuration. 42 | ;; 43 | ;; If you have good ideas about what should be added please file an 44 | ;; issue on the github tracker. 45 | ;; 46 | ;; For more info, see github readme at 47 | ;; https://github.com/Fuco1/smartparens 48 | 49 | ;;; Code: 50 | 51 | (require 'smartparens) 52 | 53 | ;;; Local pairs for ML-family languages 54 | 55 | (sp-with-modes '(fsharp-mode) 56 | (sp-local-pair "(*" "*)" )) 57 | 58 | (sp-with-modes '(tuareg-mode) 59 | ;; Disable ` because it is used in polymorphic variants 60 | (sp-local-pair "`" nil :actions nil) 61 | ;; Disable ' because it is used in value names and types 62 | (sp-local-pair "'" nil :actions nil) 63 | (sp-local-pair "{|" "|}" ) ;; multi-line string 64 | (sp-local-pair "[|" "|]" ) ;; array 65 | (sp-local-pair "sig" "end" ) ;; signature 66 | (sp-local-pair "struct" "end" ) ;; module 67 | (sp-local-pair "(*" "*)" )) ;; comment 68 | 69 | ;; Ignore punctuation, so we can split ~(foo) to ~foo. 70 | (add-to-list 'sp-sexp-prefix (list 'tuareg-mode 'syntax "")) 71 | 72 | (sp-with-modes '(reason-mode) 73 | ;; Disable ` because it is used in polymorphic variants 74 | (sp-local-pair "`" nil :actions nil) 75 | ;; Disable ' because it is used in value names and types 76 | (sp-local-pair "'" nil :actions nil) 77 | (sp-local-pair "/*" "*/" )) 78 | 79 | (provide 'smartparens-ml) 80 | ;;; smartparens-ml.el ends here 81 | -------------------------------------------------------------------------------- /smartparens-scala.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-scala.el --- Additional configuration for Scala based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2018, 2021 Greg Nwosu 4 | 5 | ;; Author: Greg Nwosu 6 | ;; Maintainer: Greg Nwosu 7 | ;; Created: 8 July 2015 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Scala based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-scala) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | ;; Scala has no sexp suffices. This fixes slurping 51 | ;; import scala.mutable{|} ListBuffer, Set ---the comma should not travel with the closing 52 | ;; paren 53 | (--each '(scala-mode inferior-scala-mode) 54 | (add-to-list 'sp-sexp-suffix (list it 'regexp ""))) 55 | 56 | (defun sp-scala-wrap-with-indented-newlines (_1 action _2) 57 | "Post handler for the wrap ACTION, putting the region on indented newlines." 58 | (when (eq action 'wrap) 59 | (indent-for-tab-command) 60 | (sp-get sp-last-wrapped-region 61 | (let ((beg :beg-in) 62 | (end :end-in)) 63 | (save-excursion 64 | (goto-char end) 65 | (newline-and-indent)) 66 | (save-excursion 67 | (goto-char beg) 68 | (newline)) 69 | (indent-region beg end))))) 70 | 71 | (sp-local-pair 'scala-mode "(" nil 72 | :post-handlers '(("||\n[i]" "RET") 73 | ("| " "SPC"))) 74 | 75 | (sp-local-pair 'scala-mode "{" nil 76 | :post-handlers '(("||\n[i]" "RET") 77 | ("| " "SPC") 78 | sp-scala-wrap-with-indented-newlines)) 79 | 80 | (sp-local-pair 'scala-mode "\"\"\"" "\"\"\"") 81 | 82 | (provide 'smartparens-scala) 83 | ;;; smartparens-scala.el ends here 84 | -------------------------------------------------------------------------------- /test/smartparens-delayed-hook-test.el: -------------------------------------------------------------------------------- 1 | (ert-deftest sp-test-delayed-hook-should-trigger-on-RET () 2 | (cl-letf (((symbol-function 'sp-test-insert-space) 3 | (lambda (&rest _) 4 | (insert " ")))) 5 | (let ((sp-pairs '((emacs-lisp-mode 6 | (:open "(" :close ")" :actions (insert wrap autoskip navigate) 7 | :post-handlers ((sp-test-insert-space "RET"))))))) 8 | (sp-test-with-temp-elisp-buffer "" 9 | (execute-kbd-macro "(") 10 | (execute-kbd-macro (kbd "RET")) 11 | (insert "|") 12 | (should (equal (buffer-string) "( 13 | |)")))))) 14 | 15 | (ert-deftest sp-test-delayed-hook-should-not-trigger-on-a () 16 | (cl-letf (((symbol-function 'sp-test-insert-space) 17 | (lambda (&rest _) 18 | (insert " ")))) 19 | (let ((sp-pairs '((emacs-lisp-mode 20 | (:open "(" :close ")" :actions (insert wrap autoskip navigate) 21 | :post-handlers ((sp-test-insert-space "RET"))))))) 22 | (sp-test-with-temp-elisp-buffer "" 23 | (execute-kbd-macro "(") 24 | (execute-kbd-macro (kbd "a")) 25 | (insert "|") 26 | (should (equal (buffer-string) "(a|)")))))) 27 | 28 | (ert-deftest sp-test-delayed-hook-should-trigger-on-my/newline () 29 | (cl-letf (((symbol-function 'my/test-newline) 30 | (lambda (&rest _) 31 | (interactive) 32 | (insert "\n"))) 33 | ((symbol-function 'sp-test-insert-space) 34 | (lambda (&rest _) 35 | (insert " ")))) 36 | (let ((sp-pairs '((emacs-lisp-mode 37 | (:open "(" :close ")" :actions (insert wrap autoskip navigate) 38 | :post-handlers ((sp-test-insert-space my/test-newline))))))) 39 | (sp-test-with-temp-elisp-buffer "" 40 | (execute-kbd-macro "(") 41 | (setq this-command 'my/test-newline) 42 | (call-interactively 'my/test-newline) 43 | (run-hooks 'post-command-hook) 44 | (insert "|") 45 | (should (equal (buffer-string) "( 46 | |)")))))) 47 | 48 | (ert-deftest sp-test-delayed-hook-should-not-trigger-on-newline () 49 | (cl-letf (((symbol-function 'my/test-newline) 50 | (lambda (&rest _) 51 | (interactive) 52 | (insert "\n"))) 53 | ((symbol-function 'newline) 54 | (lambda (&rest _) 55 | (interactive) 56 | (insert "\n"))) 57 | ((symbol-function 'sp-test-insert-space) 58 | (lambda (&rest _) 59 | (insert " ")))) 60 | (let ((sp-pairs '((emacs-lisp-mode 61 | (:open "(" :close ")" :actions (insert wrap autoskip navigate) 62 | :post-handlers ((sp-test-insert-space my/test-newline))))))) 63 | (sp-test-with-temp-elisp-buffer "" 64 | (execute-kbd-macro "(") 65 | (setq this-command 'newline) 66 | (call-interactively 'newline) 67 | (run-hooks 'post-command-hook) 68 | (insert "|") 69 | (should (equal (buffer-string) "( 70 | |)")))))) 71 | -------------------------------------------------------------------------------- /test/smartparens-barf-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | 3 | (ert-deftest sp-test-sp-forward-barf-sexp-634 () 4 | (let ((sp-barf-move-point-with-delimiter nil)) 5 | (sp-test-with-temp-elisp-buffer "(let ((a 4)\n ;; (fail)\n |(+ 1)\n ))\n" 6 | (call-interactively 'sp-forward-barf-sexp) 7 | (sp-buffer-equals "(let ((a 4))\n ;; (fail)\n (+ 1)\n )\n") 8 | (call-interactively 'sp-forward-barf-sexp) 9 | (sp-buffer-equals "(let ((a 4)))\n;; (fail)\n|(+ 1)\n\n")))) 10 | 11 | (ert-deftest sp-test-sp-forward-barf-918-move-point-with-closing-enabled () 12 | (let ((sp-barf-move-point-with-delimiter t)) 13 | (sp-test-with-temp-elisp-buffer "(hello world\n\n | what\n is this)" 14 | (call-interactively 'sp-forward-barf-sexp) 15 | (sp-buffer-equals "(hello world\n\n | what\n is) this") 16 | (call-interactively 'sp-forward-barf-sexp) 17 | (sp-buffer-equals "(hello world\n\n | what)\nis this") 18 | (call-interactively 'sp-forward-barf-sexp) 19 | (sp-buffer-equals "(hello world|)\n\nwhat\nis this")))) 20 | 21 | (ert-deftest sp-test-sp-forward-barf-918-move-point-with-closing-disabled () 22 | (let ((sp-barf-move-point-with-delimiter nil)) 23 | (sp-test-with-temp-elisp-buffer "(hello world\n\n | what\n is this)" 24 | (call-interactively 'sp-forward-barf-sexp) 25 | (sp-buffer-equals "(hello world\n\n | what\n is) this") 26 | (call-interactively 'sp-forward-barf-sexp) 27 | (sp-buffer-equals "(hello world\n\n | what)\nis this") 28 | (call-interactively 'sp-forward-barf-sexp) 29 | (sp-buffer-equals "(hello world)\n\n|what\nis this")))) 30 | 31 | (ert-deftest sp-test-sp-backward-barf-918-move-point-with-opening-enabled () 32 | (let ((sp-barf-move-point-with-delimiter t)) 33 | (sp-test-with-temp-elisp-buffer "(hello world\n\n | what\n is this)" 34 | (call-interactively 'sp-backward-barf-sexp) 35 | (sp-buffer-equals "hello (world\n\n | what\n is this)") 36 | (call-interactively 'sp-backward-barf-sexp) 37 | (sp-buffer-equals "hello world\n\n(|what\n is this)") 38 | (call-interactively 'sp-backward-barf-sexp) 39 | (sp-buffer-equals "hello world\n\nwhat\n(|is this)")))) 40 | 41 | (ert-deftest sp-test-sp-backward-barf-918-move-point-with-opening-enabled-with-prefix () 42 | (let ((sp-barf-move-point-with-delimiter t)) 43 | (sp-test-with-temp-elisp-buffer ",@(hello world\n\n | what\n is this)" 44 | (call-interactively 'sp-backward-barf-sexp) 45 | (sp-buffer-equals "hello ,@(world\n\n | what\n is this)") 46 | (call-interactively 'sp-backward-barf-sexp) 47 | (sp-buffer-equals "hello world\n\n,@(|what\n is this)") 48 | (call-interactively 'sp-backward-barf-sexp) 49 | (sp-buffer-equals "hello world\n\nwhat\n,@(|is this)")))) 50 | 51 | (ert-deftest sp-test-sp-backward-barf-918-move-point-with-opening-disabled () 52 | (let ((sp-barf-move-point-with-delimiter nil)) 53 | (sp-test-with-temp-elisp-buffer "(hello world\n\n | what\n is this)" 54 | (call-interactively 'sp-backward-barf-sexp) 55 | (sp-buffer-equals "hello (world\n\n | what\n is this)") 56 | (call-interactively 'sp-backward-barf-sexp) 57 | (sp-buffer-equals "hello world\n\n|(what\n is this)")))) 58 | -------------------------------------------------------------------------------- /smartparens-lua.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-lua.el --- Additional configuration for Lua based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2013-2014, 2016-2018 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 3 August 2013 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Lua based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-lua) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (defun sp-lua-post-keyword-insert (id action _context) 51 | "ID, ACTION, CONTEXT." 52 | (cond 53 | ((eq action 'insert) 54 | (cond 55 | ((member id '("while" "for")) 56 | (insert " do") 57 | (save-excursion (newline-and-indent)) 58 | (backward-char 3)) 59 | ((equal id "if") 60 | (insert " then") 61 | (save-excursion (newline-and-indent)) 62 | (backward-char 5)) 63 | ((equal id "function") 64 | (save-excursion (newline-and-indent)) 65 | (insert " ")))))) 66 | 67 | ;; all the pairs are expanded only if followed by "SPC" event. This 68 | ;; will reduce false positives like 'dIFficult' to trigger. 69 | (sp-with-modes '(lua-mode lua-ts-mode) 70 | (sp-local-pair "if" "end" 71 | :when '(("SPC")) 72 | :unless '(sp-in-comment-p sp-in-string-p) 73 | :post-handlers '(sp-lua-post-keyword-insert)) 74 | (sp-local-pair "function" "end" 75 | :when '(("SPC")) 76 | :unless '(sp-in-comment-p sp-in-string-p) 77 | :post-handlers '(sp-lua-post-keyword-insert)) 78 | (sp-local-pair "for" "end" 79 | :when '(("SPC")) 80 | :unless '(sp-in-comment-p sp-in-string-p) 81 | :post-handlers '(sp-lua-post-keyword-insert)) 82 | (sp-local-pair "while" "end" 83 | :when '(("SPC")) 84 | :unless '(sp-in-comment-p sp-in-string-p) 85 | :post-handlers '(sp-lua-post-keyword-insert)) 86 | ) 87 | 88 | (provide 'smartparens-lua) 89 | 90 | ;;; smartparens-lua.el ends here 91 | -------------------------------------------------------------------------------- /smartparens-markdown.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-markdown.el --- Additional configuration for Markdown based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2018 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 11th May 2017 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Markdown based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-markdown) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | (require 'smartparens-text) 50 | (eval-when-compile 51 | (defvar markdown-gfm-use-electric-backquote)) 52 | 53 | 54 | (defun sp-gfm-electric-backquote-p (_id action _context) 55 | "Do not insert ```...``` pair if that would be handled by `markdown-electric-backquote'." 56 | (and (eq action 'insert) 57 | markdown-gfm-use-electric-backquote 58 | (sp--looking-back-p "^```"))) 59 | 60 | (defun sp--gfm-point-after-word-p (id action _context) 61 | "Return t if point is after a word, nil otherwise. 62 | This predicate is only tested on \"insert\" action." 63 | (when (eq action 'insert) 64 | (sp--looking-back-p (concat "\\(\\sw\\)" (regexp-quote id))))) 65 | 66 | (defun sp--gfm-skip-asterisk (_ms mb _me) 67 | "Non-nil if we should ignore this asterisk as a delimiter." 68 | (save-excursion 69 | (goto-char mb) 70 | (save-match-data (looking-at "^\\* ")))) 71 | 72 | (sp-with-modes '(markdown-mode gfm-mode) 73 | (sp-local-pair "*" "*" 74 | :unless '(sp--gfm-point-after-word-p sp-point-at-bol-p) 75 | :post-handlers '(("[d1]" "SPC")) 76 | :skip-match 'sp--gfm-skip-asterisk) 77 | (sp-local-pair "**" "**") 78 | (sp-local-pair "_" "_" :unless '(sp-point-after-word-p))) 79 | 80 | (sp-with-modes 'markdown-mode 81 | (sp-local-pair "```" "```")) 82 | 83 | (sp-with-modes 'gfm-mode 84 | (sp-local-pair "`" "`" :unless '(:add sp-gfm-electric-backquote-p)) 85 | (sp-local-pair "```" "```" :unless '(:add sp-gfm-electric-backquote-p))) 86 | 87 | (provide 'smartparens-markdown) 88 | ;;; smartparens-markdown.el ends here 89 | -------------------------------------------------------------------------------- /test/smartparens-ess-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-ess) 2 | (require 'f) 3 | 4 | 5 | ;; ESS load helpers 6 | (defvar sp-ess-lisp-path 7 | (f-join (f-dirname (locate-library "ess-autoloads")) "lisp")) 8 | 9 | (add-to-list 'load-path sp-ess-lisp-path) 10 | 11 | 12 | (require 'ess-site) 13 | 14 | 15 | (defun sp-test--ess-mode () 16 | (shut-up (R-mode))) 17 | 18 | (ert-deftest sp-test-ess-slurp-forward () 19 | (sp-test-with-temp-buffer 20 | "(|) v[1, 2] ,3" 21 | (sp-test--ess-mode) 22 | (sp-forward-slurp-sexp 2) 23 | (should (equal (buffer-string) "(v[1, 2], 3)")))) 24 | 25 | (ert-deftest sp-test-ess-slurp-operators () 26 | (sp-test-with-temp-buffer 27 | "(|) v [1, 2]%in%c (1, 2)" 28 | (sp-test--ess-mode) 29 | (sp-forward-slurp-sexp 5) 30 | (should (equal (buffer-string) "(v[1, 2] %in% c(1, 2))")))) 31 | 32 | (ert-deftest sp-test-ess-slurp-backward () 33 | (sp-test-with-temp-buffer 34 | "v [1, 2] ,3 (|)" 35 | (sp-test--ess-mode) 36 | (sp-backward-slurp-sexp 3) 37 | (should (equal (buffer-string) "(v[1, 2], 3)")))) 38 | 39 | (ert-deftest sp-test-ess-raise-sexp () 40 | (sp-test-with-temp-buffer 41 | "list(a = v|[,2],)" 42 | (sp-test--ess-mode) 43 | (sp-raise-sexp) 44 | (should (equal (buffer-string) "v[,2]")))) 45 | 46 | (ert-deftest sp-test-ess-dont-pair-quote-in-comment () 47 | (sp-test-with-temp-buffer "# foo|" 48 | (sp-test--ess-mode) 49 | (execute-kbd-macro "'") 50 | (sp-buffer-equals "# foo'|"))) 51 | 52 | ;; #813 53 | (ert-deftest sp-test-ess-skip-to-pair-should-not-look-for-prefix-at-closing-delimiter () 54 | (sp-test-with-temp-buffer "mean(mtcars$mpg|)" 55 | (sp-test--ess-mode) 56 | (sp-backward-kill-word 1) 57 | (sp-buffer-equals "mean(mtcars$|)"))) 58 | 59 | (prog1 "#821 sp-backward-kill-word skips over prefix and does not 60 | kill it as a word/symbol" 61 | (ert-deftest sp-test-ess-prefix-resolution-ignored-for-backward-kill-symbol--string () 62 | (sp-test-with-temp-buffer "mean(\"foo|\")" 63 | (sp-test--ess-mode) 64 | (sp-backward-kill-word 1) 65 | (sp-buffer-equals "mean(\"|\")"))) 66 | 67 | (ert-deftest sp-test-ess-prefix-resolution-ignored-for-backward-kill-symbol--function-call () 68 | (sp-test-with-temp-buffer "ggplot(mtcars, aes(mpg, am)) + facet_wrap|()" 69 | (sp-test--ess-mode) 70 | (sp-backward-kill-word 1) 71 | (sp-buffer-equals "ggplot(mtcars, aes(mpg, am)) + facet_|()")))) 72 | 73 | (prog1 "Test the new R lambda function syntax" 74 | (ert-deftest sp-test-ess-short-lambda-function-in-code () 75 | (sp-test-with-temp-buffer "|" 76 | (sp-test--ess-mode) 77 | (execute-kbd-macro "\\(foo") 78 | (sp-buffer-equals "\\(foo|)"))) 79 | 80 | (ert-deftest sp-test-ess-short-lambda-function-in-string () 81 | (sp-test-with-temp-buffer "\"|\"" 82 | (sp-test--ess-mode) 83 | (execute-kbd-macro "\\(foo") 84 | (sp-buffer-equals "\"\\(foo|\\)\"")))) 85 | 86 | ;; #821 87 | (sp-ert-deftest sp-test-ess-backwards-kill-word 88 | :mode 'ess-r-mode 89 | (sp-test-complex "c(\"test\", \"one\")|" 90 | (sp-backward-kill-word 1) 91 | "c(\"test\", \"|\")") 92 | (sp-test-complex "c(\"test\", \"one\"|)" 93 | (sp-backward-kill-word 1) 94 | "c(\"test\", \"|\")") 95 | (sp-test-complex "ggplot(mtcars, aes(mpg, am)) + 96 | facet_wrap|()" 97 | (sp-backward-kill-word 1) 98 | "ggplot(mtcars, aes(mpg, am)) + 99 | facet_|()")) 100 | -------------------------------------------------------------------------------- /smartparens-org.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-org.el --- Configuration for Org mode. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2017-2019 Matúš Goljer 4 | 5 | ;; Author: Matúš Goljer 6 | ;; Maintainer: Matúš Goljer 7 | ;; Version: 0.0.1 8 | ;; Created: 15th January 2017 9 | ;; Keywords: languages 10 | 11 | ;; This program is free software; you can redistribute it and/or 12 | ;; modify it under the terms of the GNU General Public License 13 | ;; as published by the Free Software Foundation; either version 3 14 | ;; of the License, or (at your option) any later version. 15 | 16 | ;; This program is distributed in the hope that it will be useful, 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | ;; GNU General Public License for more details. 20 | 21 | ;; You should have received a copy of the GNU General Public License 22 | ;; along with this program. If not, see . 23 | 24 | ;;; Commentary: 25 | 26 | ;; This file provides some additional configuration for Org based 27 | ;; modes. To use it, simply add: 28 | ;; 29 | ;; (require 'smartparens-org) 30 | ;; 31 | ;; into your configuration. You can use this in conjunction with the 32 | ;; default config or your own configuration. 33 | ;; 34 | ;; If you have good ideas about what should be added please file an 35 | ;; issue on the github tracker. 36 | ;; 37 | ;; For more info, see github readme at 38 | ;; https://github.com/Fuco1/smartparens 39 | 40 | ;;; Code: 41 | 42 | (require 'smartparens) 43 | (require 'smartparens-text) 44 | 45 | (defun sp--org-skip-asterisk (_ms mb me) 46 | "Non-nil if the asterisk is part of the outline marker." 47 | (save-excursion 48 | (goto-char mb) 49 | (beginning-of-line) 50 | (let ((skip-distance (skip-chars-forward "*"))) 51 | (if (= skip-distance 1) 52 | (not (memq (syntax-class (syntax-after (point))) '(2 3))) 53 | (<= me (point)))))) 54 | 55 | (defun sp-org-point-after-left-square-bracket-p (id action _context) 56 | "Return t if point is after a left square bracket, nil otherwise. 57 | This predicate is only tested on \"insert\" action." 58 | (when (eq action 'insert) 59 | (sp--looking-back-p (concat "\\[" (regexp-quote id))))) 60 | 61 | (defun sp-org-inside-inline-code (_id action _context) 62 | (when (eq action 'insert) 63 | (when-let ((expr (sp-get-stringlike-expression))) 64 | (sp-get expr (member :op '("~" "=")))))) 65 | 66 | (sp-with-modes 'org-mode 67 | (sp-local-pair "*" "*" 68 | :unless '(sp-point-after-word-p 69 | sp-point-at-bol-p 70 | sp-org-inside-inline-code 71 | ) 72 | :skip-match 'sp--org-skip-asterisk) 73 | (sp-local-pair "_" "_" :unless '(sp-point-after-word-p 74 | sp-org-inside-inline-code 75 | )) 76 | (sp-local-pair "/" "/" :unless '(sp-point-after-word-p 77 | sp-org-point-after-left-square-bracket-p 78 | sp-org-inside-inline-code 79 | ) 80 | :post-handlers '(("[d1]" "SPC"))) 81 | (sp-local-pair "~" "~" :unless '(sp-point-after-word-p) :post-handlers '(("[d1]" "SPC"))) 82 | (sp-local-pair "=" "=" :unless '(sp-point-after-word-p) :post-handlers '(("[d1]" "SPC"))) 83 | (sp-local-pair "«" "»")) 84 | 85 | (provide 'smartparens-org) 86 | ;;; smartparens-org.el ends here 87 | -------------------------------------------------------------------------------- /test/smartparens-get-prefix-test.el: -------------------------------------------------------------------------------- 1 | ;; #488, changed for #934 2 | (ert-deftest sp-test-get-prefix-full-length () 3 | (sp-test-with-temp-elisp-buffer "#'(fo|o)" 4 | (should (equal (sp--get-prefix 3 "(") "#'")))) 5 | 6 | (ert-deftest sp-test-get-prefix-unquoted-quote () 7 | (sp-test-with-temp-elisp-buffer "`'(fo|o)" 8 | (should (equal (sp--get-prefix 3 "(") "`'")))) 9 | 10 | (ert-deftest sp-test-get-prefix-shorter-prefix () 11 | (sp-test-with-temp-elisp-buffer "'(fo|o)" 12 | (should (equal (sp--get-prefix 2 "(") "'")))) 13 | 14 | (ert-deftest sp-test-get-prefix-nonsense-prefix () 15 | (sp-test-with-temp-elisp-buffer "ad(fo|o)" 16 | (should (equal (sp--get-prefix 3 "(") "")))) 17 | 18 | (ert-deftest sp-test-get-prefix-no-prefix () 19 | (sp-test-with-temp-elisp-buffer "(fo|o)" 20 | (should (equal (sp--get-prefix 1 "(") "")))) 21 | 22 | ;; 664 23 | (ert-deftest sp-test-get-prefix-which-is-a-pair-in-text-mode () 24 | (let ((sp-pairs '((t (:open "«" :close "»" :actions (navigate))))) 25 | (sp-sexp-prefix '((text-mode regexp "»")))) 26 | (sp-test-with-temp-buffer "«asdasd»|«asdasd»" 27 | (text-mode) 28 | (should (equal (sp--get-prefix (point) "«") ""))))) 29 | 30 | ;; 621 31 | (ert-deftest sp-test-get-thing-with-prefix () 32 | (let ((sp-sexp-prefix '((emacs-lisp-mode regexp "\\(?:[_]+\\)")))) 33 | (sp-test-with-temp-elisp-buffer "(_|(abc))" 34 | (should (equal (sp-get-thing) 35 | '(:beg 3 :end 8 :op "(" :cl ")" :prefix "_" :suffix "")))) 36 | (sp-test-with-temp-elisp-buffer "(|_(abc))" 37 | (should (equal (sp-get-thing) 38 | '(:beg 3 :end 8 :op "(" :cl ")" :prefix "_" :suffix "")))))) 39 | 40 | ;; #812 41 | (ert-deftest sp-test-get-prefix-which-is-marked-with-special-prefix-flag () 42 | (let ((sp-sexp-prefix nil)) 43 | (sp-test-with-temp-elisp-buffer "?|foo" 44 | (with-syntax-table (make-syntax-table) 45 | (modify-syntax-entry ?? "_ p") 46 | (should (equal (sp--get-prefix) "?")))))) 47 | 48 | (prog1 "sp-test-get-prefix-for-skip-backward-to-symbol-respects-pair-prefix" 49 | (ert-deftest sp-test-get-prefix-for-skip-backward-to-symbol-respects-mode-prefix () 50 | (let ((sp-sexp-prefix '((emacs-lisp-mode regexp "\\(?:aaa\\)")))) 51 | (sp-test-with-temp-elisp-buffer "asd (aaa|(abc))" 52 | (sp-skip-backward-to-symbol) 53 | (sp-buffer-equals "asd (|aaa(abc))")))) 54 | 55 | (ert-deftest sp-test-get-prefix-for-skip-backward-to-symbol-respects-pair-prefix () 56 | (let ((sp-sexp-prefix '((emacs-lisp-mode regexp "\\(?:aaa\\)")))) 57 | (sp-test-with-temp-elisp-buffer "asd (aaa|(abc))" 58 | (let ((sp-pairs '((t (:open "(" :close ")" :actions (insert wrap autoskip navigate))) 59 | (emacs-lisp-mode (:open "(" :close ")" :actions (insert wrap autoskip navigate) :prefix ""))))) 60 | (sp--update-local-pairs) 61 | (sp-skip-backward-to-symbol) 62 | (sp-buffer-equals "asd (aaa|(abc))")))))) 63 | 64 | (ert-deftest sp-test-get-prefix-always-return-string () 65 | "Previously in case of a pair-specific prefix we could return 66 | nil if there was no match." 67 | (let ((sp-sexp-prefix '((emacs-lisp-mode regexp "\\(?:aaa\\)")))) 68 | (sp-test-with-temp-elisp-buffer "asd (aaa|(abc))" 69 | (let ((sp-pairs '((t (:open "(" :close ")" :actions (insert wrap autoskip navigate))) 70 | (emacs-lisp-mode (:open "(" :close ")" :actions (insert wrap autoskip navigate) :prefix "x"))))) 71 | (sp--update-local-pairs) 72 | (should (equal (sp--get-prefix (point) "(") "")))))) 73 | -------------------------------------------------------------------------------- /test/smartparens-cua-selection-test.el: -------------------------------------------------------------------------------- 1 | ;; Tests for cua-selection-mode and smartparens integration 2 | 3 | (defmacro sp-test-cuasel (initial &rest forms) 4 | (declare (indent 1)) 5 | `(unwind-protect 6 | (progn 7 | (cua-selection-mode 1) 8 | (sp-test-with-temp-elisp-buffer ,initial 9 | (smartparens-strict-mode 1) 10 | ,@forms)) 11 | (cua-selection-mode -1))) 12 | 13 | (ert-deftest sp-test-cua-selection-mode-delete-region-strict-valid () 14 | (sp-test-cuasel "(fo|o bMar)" 15 | (execute-kbd-macro "x") 16 | (sp-buffer-equals "(fox|ar)"))) 17 | 18 | (ert-deftest sp-test-cua-selection-mode-delete-region-strict-invalid () 19 | (sp-test-cuasel "(fo|o) bMar" 20 | (execute-kbd-macro "x") 21 | (sp-buffer-equals "(fo|o) bMar"))) 22 | 23 | (ert-deftest sp-test-cua-selection-mode-delete-region-nonstrict-valid () 24 | (sp-test-cuasel "(fo|o bMar)" 25 | (smartparens-strict-mode -1) 26 | (execute-kbd-macro "x") 27 | (sp-buffer-equals "(fox|ar)"))) 28 | 29 | (ert-deftest sp-test-cua-selection-mode-delete-region-nonstrict-invalid () 30 | (sp-test-cuasel "(fo|o) bMar" 31 | (smartparens-strict-mode -1) 32 | (execute-kbd-macro "x") 33 | (sp-buffer-equals "(fox|ar"))) 34 | 35 | ;; Calling sp-delete-char 36 | (ert-deftest sp-test-cua-selection-mode-delete-char-can-not-kill-invalid-region () 37 | (sp-test-cuasel "(fo|o) bMar" 38 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 39 | (execute-kbd-macro "d")) 40 | (sp-buffer-equals "(fo|o) bMar"))) 41 | 42 | (ert-deftest sp-test-cua-selection-mode-delete-char-can-kill-valid-region () 43 | (sp-test-cuasel "(fo|o bMar)" 44 | (sp-test-with-temp-binding ("d" 'sp-delete-char) 45 | (execute-kbd-macro "d")) 46 | (sp-buffer-equals "(fo|ar)"))) 47 | 48 | (ert-deftest sp-test-cua-selection-mode-nonstrict-delete-char-can-kill-invalid-region () 49 | (sp-test-cuasel "(fo|o) bMar" 50 | (smartparens-strict-mode -1) 51 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 52 | (execute-kbd-macro "d")) 53 | (sp-buffer-equals "(fo|ar"))) 54 | 55 | (ert-deftest sp-test-cua-selection-mode-nonstrict-delete-char-can-kill-valid-region () 56 | (sp-test-cuasel "(fo|o bMar)" 57 | (smartparens-strict-mode -1) 58 | (sp-test-with-temp-binding ("d" 'sp-delete-char) 59 | (execute-kbd-macro "d")) 60 | (sp-buffer-equals "(fo|ar)"))) 61 | 62 | ;; Calling sp-backward-delete-char 63 | (ert-deftest sp-test-cua-selection-mode-backward-delete-char-can-not-kill-invalid-region () 64 | (sp-test-cuasel "(fo|o) bMar" 65 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 66 | (execute-kbd-macro "d")) 67 | (sp-buffer-equals "(fo|o) bMar"))) 68 | 69 | (ert-deftest sp-test-cua-selection-mode-backward-delete-char-can-kill-valid-region () 70 | (sp-test-cuasel "(fo|o bMar)" 71 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 72 | (execute-kbd-macro "d")) 73 | (sp-buffer-equals "(fo|ar)"))) 74 | 75 | (ert-deftest sp-test-cua-selection-mode-nonstrict-backward-delete-char-can-kill-invalid-region () 76 | (sp-test-cuasel "(fo|o) bMar" 77 | (smartparens-strict-mode -1) 78 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 79 | (execute-kbd-macro "d")) 80 | (sp-buffer-equals "(fo|ar"))) 81 | 82 | (ert-deftest sp-test-cua-selection-mode-nonstrict-backward-delete-char-can-kill-valid-region () 83 | (sp-test-cuasel "(fo|o bMar)" 84 | (smartparens-strict-mode -1) 85 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 86 | (execute-kbd-macro "d")) 87 | (sp-buffer-equals "(fo|ar)"))) 88 | -------------------------------------------------------------------------------- /test/smartparens-region-ok-test.el: -------------------------------------------------------------------------------- 1 | (defmacro sp-test--string-valid-p (str &optional init) 2 | `(sp-test-with-temp-buffer ,str 3 | ,(if init `,init '(emacs-lisp-mode)) 4 | (and (sp-region-ok-p (point-min) (point-max)) 5 | (sp-region-ok-p (point-max) (point-min))))) 6 | 7 | (ert-deftest sp-test-region-ok-unbalanced-paren () 8 | (should-not (sp-test--string-valid-p "foo)"))) 9 | 10 | (ert-deftest sp-test-region-ok-unbalanced-string () 11 | (should-not (sp-test--string-valid-p "foo\""))) 12 | 13 | (ert-deftest sp-test-region-ok-no-sexp () 14 | (should (sp-test--string-valid-p "foo"))) 15 | 16 | (ert-deftest sp-test-region-ok-balanced-string () 17 | (should (sp-test--string-valid-p "\"foo\""))) 18 | 19 | (ert-deftest sp-test-region-ok-balanced-string-with-escaped-quote () 20 | (should (sp-test--string-valid-p "\"foo \\\" bar\""))) 21 | 22 | (ert-deftest sp-test-region-ok-balanced-parens () 23 | (should (sp-test--string-valid-p "(foo)"))) 24 | 25 | (ert-deftest sp-test-region-ok-balanced-parens-with-newline () 26 | (should (sp-test--string-valid-p "(foo)\n\n"))) 27 | 28 | (ert-deftest sp-test-region-ok-flipped-parens () 29 | (should-not (sp-test--string-valid-p ")foo("))) 30 | 31 | (ert-deftest sp-test-region-ok-c++-mode-no-sexp () 32 | (should (sp-test--string-valid-p "foo;" (c++-mode)))) 33 | 34 | (ert-deftest sp-test-region-ok-c++-mode-balanced-sexp-with-newline () 35 | (should (sp-test--string-valid-p "{ 36 | animDivisor = FAWorld::World::getTicksInPeriod(0.1f); 37 | }" (c++-mode)))) 38 | 39 | (ert-deftest sp-test-region-ok-c++-mode-balanced-sexp-single-line () 40 | (should (sp-test--string-valid-p "{ animDivisor = FAWorld::World::getTicksInPeriod(0.1f); }" (c++-mode)))) 41 | 42 | (ert-deftest sp-test-region-ok-c++-mode-unbalanced-sexp-single-line () 43 | (should-not (sp-test--string-valid-p "animDivisor = FAWorld::World::getTicksInPeriod(0.1f); }" (c++-mode)))) 44 | 45 | (ert-deftest sp-test-region-ok-balanced-parens-with-skip-match () 46 | (let ((sp-pairs '((t . ((:open "(" :close ")" 47 | :actions (insert wrap autoskip navigate) 48 | :skip-match (lambda (ms mb me) 49 | (save-excursion 50 | (goto-char mb) 51 | (sp--looking-back-p "skip" 4))))))))) 52 | (should (sp-test--string-valid-p "(fo skip) o)")))) 53 | 54 | (ert-deftest sp-test-region-ok-with-non-navigable-pairs () 55 | (let ((sp-pairs '((t . ((:open "*" :close "*" :actions (wrap))))))) 56 | (should (sp-test--string-valid-p "*a*")))) 57 | 58 | (ert-deftest sp-test-region-ok-with-trailing-garbage () 59 | (should (sp-test--string-valid-p "(foo) asdf!$#$^"))) 60 | 61 | (ert-deftest sp-test-region-ok-unbalanced-paren-in-string () 62 | (should (sp-test--string-valid-p "(foo \")\")"))) 63 | 64 | (ert-deftest sp-test-region-ok-balanced-paren-in-latex () 65 | (let ((sp-pairs '((t . ((:open "\\(" :close "\\)" :actions (insert wrap autoskip navigate)) 66 | (:open "(" :close ")" :actions (insert wrap autoskip navigate))))))) 67 | (sp-test-with-temp-buffer "foo \\(foo\\) foo" 68 | (latex-mode) 69 | (should (sp-region-ok-p (point-min) (point-max)))))) 70 | 71 | (ert-deftest sp-test-region-ok-unbalanced-paren-in-latex () 72 | (let ((sp-pairs '((t . ((:open "\\(" :close "\\)" :actions (insert wrap autoskip navigate)) 73 | (:open "(" :close ")" :actions (insert wrap autoskip navigate))))))) 74 | (sp-test-with-temp-buffer "foo \\(foo foo" 75 | (latex-mode) 76 | (should-not (sp-region-ok-p (point-min) (point-max)))))) 77 | -------------------------------------------------------------------------------- /test/smartparens-delete-pair-test.el: -------------------------------------------------------------------------------- 1 | (require 'python) 2 | 3 | (ert-deftest sp-test-delete-pair () 4 | (sp-test-with-temp-elisp-buffer "(|)" 5 | (smartparens-strict-mode -1) 6 | (delete-backward-char 1) 7 | (should (equal (buffer-string) "")))) 8 | 9 | (ert-deftest sp-test-delete-pair-closing () 10 | (let ((sp-pairs sp--test-basic-pairs)) 11 | (sp-test-with-temp-elisp-buffer "\\{\\}|" 12 | (smartparens-strict-mode -1) 13 | (delete-backward-char 1) 14 | (should (equal (buffer-string) "\\{"))))) 15 | 16 | (ert-deftest sp-test-delete-pair-opening () 17 | (let ((sp-pairs sp--test-basic-pairs)) 18 | (sp-test-with-temp-elisp-buffer "\\{|" 19 | (smartparens-strict-mode -1) 20 | (delete-backward-char 1) 21 | (should (equal (buffer-string) ""))))) 22 | 23 | (ert-deftest sp-test-delete-pair-in-org-mode-according-to-syntax () 24 | (sp-test-with-temp-buffer "\"asdasd\"| \"asdad\"" 25 | (org-mode) 26 | (smartparens-strict-mode -1) 27 | (delete-backward-char 1) 28 | (should (equal (buffer-string) "\"asdasd \"asdad\"")))) 29 | 30 | (ert-deftest sp-test-delete-pair-in-org-mode-truly-empty () 31 | (let ((sp-pairs '((t (:open "\"" :close "\"" :actions (insert wrap autoskip navigate)) 32 | (:open "(" :close ")" :actions (insert wrap autoskip navigate)))))) 33 | (sp-test-with-temp-buffer "\"asdasd\" \"|\" \"asdad\"" 34 | (org-mode) 35 | (smartparens-strict-mode -1) 36 | (delete-backward-char 1) 37 | (should (equal (buffer-string) "\"asdasd\" \"asdad\""))))) 38 | 39 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-no-strict-mode-no-spaces () 40 | "This is a test for #731." 41 | (sp-test-with-temp-elisp-buffer "\"\\\"|\"" 42 | (smartparens-strict-mode -1) 43 | (backward-delete-char 1) 44 | (sp-buffer-equals "\"|\""))) 45 | 46 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-no-strict-mode-spaces () 47 | "This is a test for #731." 48 | (sp-test-with-temp-elisp-buffer "\" \\\"| \"" 49 | (smartparens-strict-mode -1) 50 | (backward-delete-char 1) 51 | (sp-buffer-equals "\" \\| \""))) 52 | 53 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-no-strict-mode-no-spaces-python () 54 | "This is a test for #731." 55 | (sp-test-with-temp-buffer "\"\\\"|\"" 56 | (shut-up (python-mode)) 57 | (smartparens-strict-mode -1) 58 | (python-indent-dedent-line-backspace 1) 59 | (sp-buffer-equals "\"|\""))) 60 | 61 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-no-strict-mode-spaces-python () 62 | "This is a test for #731." 63 | (sp-test-with-temp-buffer "\" \\\"| \"" 64 | (shut-up (python-mode)) 65 | (smartparens-strict-mode -1) 66 | (python-indent-dedent-line-backspace 1) 67 | (sp-buffer-equals "\" \\| \""))) 68 | 69 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-strict-mode-no-spaces () 70 | "This is a test for #731." 71 | (sp-test-with-temp-elisp-buffer "\"\\\"|\"" 72 | (smartparens-strict-mode 1) 73 | (sp-backward-delete-char) 74 | (sp-buffer-equals "\"|\""))) 75 | 76 | (ert-deftest sp-test-delete-pair-escaped-double-quote-in-quotes-strict-mode-spaces () 77 | "This is a test for #731." 78 | (sp-test-with-temp-elisp-buffer "\" \\\"| \"" 79 | (smartparens-strict-mode 1) 80 | (sp-backward-delete-char) 81 | (sp-buffer-equals "\" | \""))) 82 | 83 | (ert-deftest sp-test-delete-pair-dont-delete-with-active-region () 84 | "Fixes #703" 85 | (sp-test-with-temp-elisp-buffer "(| 86 | 87 | M)" 88 | (smartparens-strict-mode -1) 89 | (call-interactively 'backward-delete-char) 90 | (should (equal (buffer-string) "()")))) 91 | -------------------------------------------------------------------------------- /test/smartparens-get-stringlike-expression-elisp-test.el: -------------------------------------------------------------------------------- 1 | (defun sp-test--stringlike-expression-parse-in-elisp (initial result &optional back) 2 | (sp-test-with-temp-elisp-buffer initial 3 | (should (equal (sp-get-stringlike-expression back) result)))) 4 | 5 | (ert-deftest sp-test-get-stringlike-expression-elisp () 6 | "Test basic stringlike expressions in `emacs-lisp-mode'." 7 | (sp-test--stringlike-expression-parse-in-elisp "|foo \"bar\" baz \"quux\" bux" '(:beg 5 :end 10 :op "\"" :cl "\"" :prefix "" :suffix "")) 8 | (sp-test--stringlike-expression-parse-in-elisp "foo |\"bar\" baz \"quux\" bux" '(:beg 5 :end 10 :op "\"" :cl "\"" :prefix "" :suffix "")) 9 | (sp-test--stringlike-expression-parse-in-elisp "foo \"|bar\" baz \"quux\" bux" '(:beg 5 :end 10 :op "\"" :cl "\"" :prefix "" :suffix "")) 10 | (sp-test--stringlike-expression-parse-in-elisp "foo \"ba|r\" baz \"quux\" bux" '(:beg 5 :end 10 :op "\"" :cl "\"" :prefix "" :suffix "")) 11 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar|\" baz \"quux\" bux" '(:beg 5 :end 10 :op "\"" :cl "\"" :prefix "" :suffix "")) 12 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\"| baz \"quux\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 13 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\" b|az \"quux\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 14 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\" baz| \"quux\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 15 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\" baz |\"quux\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 16 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\" baz \"qu|ux\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 17 | (sp-test--stringlike-expression-parse-in-elisp "foo \"bar\" baz \"quux|\" bux" '(:beg 15 :end 21 :op "\"" :cl "\"" :prefix "" :suffix "")) 18 | (sp-test--stringlike-expression-parse-in-elisp "|foo \"b\\\"ar\" baz \"q\\\"uux\" bux" '(:beg 5 :end 12 :op "\"" :cl "\"" :prefix "" :suffix "")) 19 | (sp-test--stringlike-expression-parse-in-elisp "foo |\"b\\\"ar\" baz \"q\\\"uux\" bux" '(:beg 5 :end 12 :op "\"" :cl "\"" :prefix "" :suffix "")) 20 | (sp-test--stringlike-expression-parse-in-elisp "foo \"b\\\"a|r\" baz \"q\\\"uux\" bux" '(:beg 5 :end 12 :op "\"" :cl "\"" :prefix "" :suffix "")) 21 | (sp-test--stringlike-expression-parse-in-elisp "foo \"b\\\"ar\"| baz \"q\\\"uux\" bux" '(:beg 17 :end 25 :op "\"" :cl "\"" :prefix "" :suffix "")) 22 | (sp-test--stringlike-expression-parse-in-elisp "foo \"b\\\"ar\" baz |\"q\\\"uux\" bux" '(:beg 17 :end 25 :op "\"" :cl "\"" :prefix "" :suffix "")) 23 | (sp-test--stringlike-expression-parse-in-elisp "foo \"b\\\"ar\" baz \"q\\\"uu|x\" bux" '(:beg 17 :end 25 :op "\"" :cl "\"" :prefix "" :suffix "")) 24 | (sp-test--stringlike-expression-parse-in-elisp "|foo \\\"bar\\\" baz bam \\\"quux\\\"" '(:beg 5 :end 12 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 25 | (sp-test--stringlike-expression-parse-in-elisp "foo |\\\"bar\\\" baz bam \\\"quux\\\"" '(:beg 5 :end 12 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 26 | (sp-test--stringlike-expression-parse-in-elisp "foo \\\"b|ar\\\" baz bam \\\"quux\\\"" '(:beg 5 :end 12 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 27 | (sp-test--stringlike-expression-parse-in-elisp "foo \\\"bar\\\"| baz bam \\\"quux\\\"" '(:beg 21 :end 29 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 28 | (sp-test--stringlike-expression-parse-in-elisp "foo \\\"bar\\\" baz bam |\\\"quux\\\"" '(:beg 21 :end 29 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 29 | (sp-test--stringlike-expression-parse-in-elisp "foo \\\"bar\\\" baz bam \\\"quu|x\\\"" '(:beg 21 :end 29 :op "\\\"" :cl "\\\"" :prefix "" :suffix "")) 30 | ) 31 | -------------------------------------------------------------------------------- /test/smartparens-markdown-test.el: -------------------------------------------------------------------------------- 1 | (require 'markdown-mode) 2 | (require 'smartparens-markdown) 3 | 4 | (ert-deftest sp-test-markdown-gfm-electric-backquote-disabled () 5 | "Test that tripple-backquotes are properly paired in `gfm-mode' 6 | with `markdown-gfm-use-electric-backquote' disabled." 7 | (let ((markdown-gfm-use-electric-backquote nil)) 8 | (sp-test-with-temp-buffer "|" 9 | (gfm-mode) 10 | (execute-kbd-macro "```") 11 | (sp-buffer-equals "```|```")))) 12 | 13 | (ert-deftest sp-test-markdown-gfm-electric-backquote-enabled () 14 | "Test that tripple-backquotes are properly paired in `gfm-mode' 15 | with `markdown-gfm-use-electric-backquote' enabled." 16 | (let ((markdown-gfm-use-electric-backquote t)) 17 | (sp-test-with-temp-buffer "|" 18 | (gfm-mode) 19 | (execute-kbd-macro "```php") 20 | (sp-buffer-equals "``` php 21 | | 22 | ```")))) 23 | 24 | (ert-deftest sp-test-markdown-tripple-backquote () 25 | "Test that tripple-backquotes are properly paired in `markdown-mode'." 26 | (sp-test-with-temp-buffer "|" 27 | (markdown-mode) 28 | (execute-kbd-macro "```") 29 | (sp-buffer-equals "```|```"))) 30 | 31 | (ert-deftest sp-test-markdown-insert-new-list-item () 32 | (sp-test-with-temp-buffer "|" 33 | (markdown-mode) 34 | (execute-kbd-macro "* foo bar") 35 | (sp-buffer-equals "* foo bar|"))) 36 | 37 | (ert-deftest sp-test-markdown-insert-star-pair () 38 | (sp-test-with-temp-buffer "|" 39 | (markdown-mode) 40 | (execute-kbd-macro "foo *bar") 41 | (sp-buffer-equals "foo *bar|*"))) 42 | 43 | (ert-deftest sp-test-markdown-do-not-insert-star-pair-if-followed-by-spc () 44 | (sp-test-with-temp-buffer "|" 45 | (markdown-mode) 46 | (execute-kbd-macro "foo * bar") 47 | (sp-buffer-equals "foo * bar|"))) 48 | 49 | (ert-deftest sp-test-markdown-do-not-insert-star-pair-if-preceded-by-word () 50 | (sp-test-with-temp-buffer "|" 51 | (markdown-mode) 52 | (execute-kbd-macro "foo* bar") 53 | (sp-buffer-equals "foo* bar|"))) 54 | 55 | (ert-deftest sp-test-markdown-insert-double-star-pair () 56 | (sp-test-with-temp-buffer "|" 57 | (markdown-mode) 58 | (execute-kbd-macro "foo **bar") 59 | (sp-buffer-equals "foo **bar|**"))) 60 | 61 | (ert-deftest sp-test-markdown-unwrap-single-star () 62 | (sp-test-with-temp-buffer "foo *ba|r* baz" 63 | (markdown-mode) 64 | (sp-unwrap-sexp) 65 | (sp-buffer-equals "foo ba|r baz"))) 66 | 67 | (ert-deftest sp-test-markdown-unwrap-double-star () 68 | (sp-test-with-temp-buffer "foo **ba|r** baz" 69 | (markdown-mode) 70 | (sp-unwrap-sexp) 71 | (sp-buffer-equals "foo ba|r baz"))) 72 | 73 | (ert-deftest sp-test-markdown-ignore-list-bullet-when-parsing () 74 | (sp-test-with-temp-buffer "* foo bar| * ads" 75 | (markdown-mode) 76 | (should-not (sp-get-enclosing-sexp)))) 77 | 78 | (ert-deftest sp-test-markdown-insert-underscore-pair () 79 | (sp-test-with-temp-buffer "|" 80 | (markdown-mode) 81 | (execute-kbd-macro "foo _bar") 82 | (sp-buffer-equals "foo _bar|_"))) 83 | 84 | (ert-deftest sp-test-markdown-wrap-with-star-pair () 85 | (sp-test-with-temp-buffer "foo |barM baz" 86 | (markdown-mode) 87 | (execute-kbd-macro "*") 88 | (sp-buffer-equals "foo *|barM* baz"))) 89 | 90 | (ert-deftest sp-test-markdown-wrap-with-doublestar-pair () 91 | (sp-test-with-temp-buffer "foo |barM baz" 92 | (markdown-mode) 93 | (execute-kbd-macro "**") 94 | (sp-buffer-equals "foo **|barM** baz"))) 95 | 96 | (ert-deftest sp-test-markdown-wrap-with-underscore-pair () 97 | (sp-test-with-temp-buffer "foo |barM baz" 98 | (markdown-mode) 99 | (execute-kbd-macro "_") 100 | (sp-buffer-equals "foo _|barM_ baz"))) 101 | -------------------------------------------------------------------------------- /test/smartparens-elisp-test.el: -------------------------------------------------------------------------------- 1 | (ert-deftest sp-test-elisp-invalid-hyperlink/point-before-contraction () 2 | (sp-test-with-temp-elisp-buffer "; foo|'bar" 3 | (should (sp-lisp-invalid-hyperlink-p nil 'navigate nil)))) 4 | 5 | (ert-deftest sp-test-elisp-invalid-hyperlink/point-after-contraction () 6 | (sp-test-with-temp-elisp-buffer "; foo'|bar" 7 | (should (sp-lisp-invalid-hyperlink-p nil 'navigate nil)))) 8 | 9 | (ert-deftest sp-test-elisp-invalid-hyperlink/point-before-before-punctuation () 10 | (sp-test-with-temp-elisp-buffer "; foo|'." 11 | (should-not (sp-lisp-invalid-hyperlink-p nil 'navigate nil)))) 12 | 13 | (ert-deftest sp-test-elisp-invalid-hyperlink/point-after-before-punctuation () 14 | (sp-test-with-temp-elisp-buffer "; foo'|." 15 | (should-not (sp-lisp-invalid-hyperlink-p nil 'navigate nil)))) 16 | 17 | ;; #782 18 | (ert-deftest sp-test-elisp-invalid-hyperlink/strict-mode-should-delete-over-contraction-after-hyperlink () 19 | "In case there was a hyperlink followed by punctuation and a 20 | contraction after that the parser figured that the hyperlink 21 | actually ends at the contraction because the quote before the 22 | punctuation was considered invalid." 23 | (sp-test-with-temp-elisp-buffer ";; `a-symbol-name'? I'm|" 24 | (smartparens-strict-mode 1) 25 | (sp-backward-delete-char) 26 | (sp-backward-delete-char) 27 | (sp-buffer-equals ";; `a-symbol-name'? I|"))) 28 | 29 | (prog1 "#781" 30 | (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-paren-no-space () 31 | (sp-test-with-temp-elisp-buffer "(foo|)(bar)" 32 | (call-interactively 'sp-forward-slurp-sexp) 33 | (sp-buffer-equals "(foo| (bar))") 34 | (call-interactively 'sp-forward-barf-sexp) 35 | (sp-buffer-equals "(foo|) (bar)") 36 | (call-interactively 'sp-forward-slurp-sexp) 37 | (sp-buffer-equals "(foo| (bar))"))) 38 | 39 | (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-paren-space () 40 | (sp-test-with-temp-elisp-buffer "(foo|) (bar)" 41 | (call-interactively 'sp-forward-slurp-sexp) 42 | (sp-buffer-equals "(foo| (bar))") 43 | (call-interactively 'sp-forward-barf-sexp) 44 | (sp-buffer-equals "(foo|) (bar)") 45 | (call-interactively 'sp-forward-slurp-sexp) 46 | (sp-buffer-equals "(foo| (bar))"))) 47 | 48 | (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-symbol-no-space () 49 | (sp-test-with-temp-elisp-buffer "(foo|)bar" 50 | (call-interactively 'sp-forward-slurp-sexp) 51 | (sp-buffer-equals "(foo| bar)") 52 | (call-interactively 'sp-forward-barf-sexp) 53 | (sp-buffer-equals "(foo|) bar") 54 | (call-interactively 'sp-forward-slurp-sexp) 55 | (sp-buffer-equals "(foo| bar)"))) 56 | 57 | (ert-deftest sp-test-slurp-insert-space-for-style--next-sexp-symbol-space () 58 | (sp-test-with-temp-elisp-buffer "(foo|) bar" 59 | (call-interactively 'sp-forward-slurp-sexp) 60 | (sp-buffer-equals "(foo| bar)") 61 | (call-interactively 'sp-forward-barf-sexp) 62 | (sp-buffer-equals "(foo|) bar") 63 | (call-interactively 'sp-forward-slurp-sexp) 64 | (sp-buffer-equals "(foo| bar)"))) 65 | 66 | (ert-deftest sp-test-slurp-insert-space-for-style--no-extra-space-from-empty-sexp () 67 | (sp-test-with-temp-elisp-buffer "(|)foo" 68 | (call-interactively 'sp-forward-slurp-sexp) 69 | (sp-buffer-equals "(|foo)") 70 | (call-interactively 'sp-forward-barf-sexp) 71 | (sp-buffer-equals "(|)foo"))) 72 | 73 | (ert-deftest sp-test-slurp-insert-space-for-style--next-on-new-line () 74 | (sp-test-with-temp-elisp-buffer "(foo|)\n(bar)" 75 | (call-interactively 'sp-forward-slurp-sexp) 76 | (sp-buffer-equals "(foo|\n (bar))") 77 | (call-interactively 'sp-forward-barf-sexp) 78 | (sp-buffer-equals "(foo|)\n(bar)")))) 79 | -------------------------------------------------------------------------------- /test/smartparens-get-expression-test.el: -------------------------------------------------------------------------------- 1 | (sp-ert-deftest sp-test-skip-forward-to-symbol 2 | ;; check that the syntax property is observed when determining 3 | ;; syntax #851 #1195 4 | (sp-test-with-temp-elisp-buffer "| -foo-bar" 5 | (put-text-property 2 3 'syntax-table '(1)) 6 | (sp-skip-forward-to-symbol) 7 | (sp-buffer-equals " -|foo-bar"))) 8 | 9 | (defun sp-test--get-expression-skip-before-arrow (ms mb me) 10 | (save-excursion 11 | (goto-char me) 12 | (looking-at-p "<"))) 13 | 14 | (ert-deftest sp-test-get-expression-string-when-there-is-ignored-regular-before-it-and-valid-after-it () 15 | "In case there is a non-string delimiter before a 16 | string-delimiter but it turns out it is invalid and we return a 17 | regular expression which starts after the string one, try to 18 | reparse the string expression because it might be valid and 19 | closer. 20 | 21 | foo | [<-thisisignored \"bar\" [we got this instead of the string]" 22 | (let ((sp-pairs '((t . ((:open "\"" :close "\"" :actions (insert wrap autoskip navigate)) 23 | (:open "[" :close "]" :actions (insert wrap autoskip navigate) 24 | :skip-match sp-test--get-expression-skip-before-arrow)))))) 25 | (sp-test-with-temp-elisp-buffer "foo | [<-thisisignored \"bar\" [we got this instead of the string]" 26 | (sp-get (sp-get-expression) 27 | (should (equal :op "\"")) 28 | (should (equal :beg 23)))))) 29 | 30 | (ert-deftest sp-test-get-expression-regular-when-there-is-ignored-string-before-it-and-valid-after-it () 31 | "In case there is a string delimiter before a 32 | non-string-delimiter but it turns out it is invalid and we return 33 | a string expression which starts after the regular one, try to 34 | reparse the regular expression because it might be valid and 35 | closer. 36 | 37 | foo | '<-thisisignored [brackets] `we got this instead of the brackets'" 38 | (let ((sp-pairs '((t . ((:open "'" :close "'" :actions (insert wrap autoskip navigate) 39 | :skip-match sp-test--get-expression-skip-before-arrow) 40 | (:open "[" :close "]" :actions (insert wrap autoskip navigate))))))) 41 | (sp-test-with-temp-buffer "foo | '<-thisisignored [brackets] 'we got this instead of the brackets'" 42 | (fundamental-mode) 43 | (sp-get (sp-get-expression) 44 | (should (equal :op "[")) 45 | (should (equal :beg 23)))))) 46 | 47 | (ert-deftest sp-test-get-expression-regular-when-there-is-ignored-string-before-it-and-no-after-it () 48 | "If the first delimiter we've found was skipped and then there 49 | were no more string delimiters any following regular pair was 50 | ignored as well. 51 | 52 | We should only consider valid delimiters to start parsing." 53 | (let ((sp-pairs '((t . ((:open "'" :close "'" :actions (insert wrap autoskip navigate) 54 | :skip-match sp-test--get-expression-skip-before-arrow) 55 | (:open "[" :close "]" :actions (insert wrap autoskip navigate))))))) 56 | (sp-test-with-temp-buffer "skip this '< and [pick up this]" 57 | (fundamental-mode) 58 | (sp-get (sp-get-expression) 59 | (should (equal :op "[")))))) 60 | 61 | (ert-deftest sp-test-get-expression-regular-when-there-are-multiple-ignored-strings-before-it-and-no-after-it () 62 | "If the first delimiter we've found was skipped and then there 63 | were no more string delimiters any following regular pair was 64 | ignored as well. 65 | 66 | We should only consider valid delimiters to start parsing." 67 | (let ((sp-pairs '((t . ((:open "'" :close "'" :actions (insert wrap autoskip navigate) 68 | :skip-match sp-test--get-expression-skip-before-arrow) 69 | (:open "*" :close "*" :actions (insert wrap autoskip navigate) 70 | :skip-match sp-test--get-expression-skip-before-arrow) 71 | (:open "[" :close "]" :actions (insert wrap autoskip navigate))))))) 72 | (sp-test-with-temp-buffer "skip this '< and also *< this and [pick up this]" 73 | (fundamental-mode) 74 | (sp-get (sp-get-expression) 75 | (should (equal :op "[")))))) 76 | -------------------------------------------------------------------------------- /test/smartparens-auctex-latex-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-latex) 2 | 3 | (ert-deftest sp-test-LaTeX-dont-insert-space-on-forward-slurp-where-not-necessary () 4 | (sp-test-with-temp-buffer "foo (|)(bar)(baz)" 5 | (LaTeX-mode) 6 | (sp-forward-slurp-sexp 2) 7 | (sp-buffer-equals "foo (|(bar)(baz))") 8 | (sp-forward-barf-sexp 2) 9 | (sp-buffer-equals "foo (|)(bar)(baz)"))) 10 | 11 | (ert-deftest sp-test-LaTeX-insert-space-on-forward-slurp-where-necessary () 12 | (sp-test-with-temp-buffer "foo (|bar)baz" 13 | (LaTeX-mode) 14 | (sp-forward-slurp-sexp) 15 | (sp-buffer-equals "foo (|bar baz)") 16 | (sp-forward-barf-sexp) 17 | (sp-buffer-equals "foo (|bar) baz"))) 18 | 19 | (ert-deftest sp-test-LaTeX-dont-insert-space-on-backward-slurp-where-not-necessary () 20 | (sp-test-with-temp-buffer "foo (bar)(baz)(|)" 21 | (LaTeX-mode) 22 | (sp-backward-slurp-sexp 2) 23 | (sp-buffer-equals "foo ((bar)(baz)|)") 24 | (sp-backward-barf-sexp 2) 25 | (sp-buffer-equals "foo (bar)(baz)(|)"))) 26 | 27 | (ert-deftest sp-test-LaTeX-insert-space-on-backward-slurp-where-necessary () 28 | (sp-test-with-temp-buffer "foo bar(baz|)" 29 | (LaTeX-mode) 30 | (sp-backward-slurp-sexp) 31 | (sp-buffer-equals "foo (bar baz|)") 32 | (sp-backward-barf-sexp) 33 | (sp-buffer-equals "foo bar (baz|)"))) 34 | 35 | (ert-deftest sp-test-LaTeX-navigate-single-quote-pair-backwards-at-opener () 36 | (sp-test-with-temp-buffer "\\foo{bar} `|foo bar'baz'" 37 | (LaTeX-mode) 38 | (should (equal (sp-get-thing t) 39 | '(:beg 11 :end 24 :op "`" :cl "'" :prefix "" :suffix ""))))) 40 | 41 | (ert-deftest sp-test-LaTeX-navigate-single-quote-pair-backwards-at-closer () 42 | (sp-test-with-temp-buffer "\\foo{bar} `foo bar'baz'|" 43 | (LaTeX-mode) 44 | (should (equal (sp-get-thing t) 45 | '(:beg 11 :end 24 :op "`" :cl "'" :prefix "" :suffix ""))))) 46 | 47 | ;; SKIP: 48 | ;; (ert-deftest sp-test-LaTeX-navigate-single-quote-pair-backwards-at-contraction () 49 | ;; (sp-test-with-temp-buffer "\\foo{bar} `foo bar'|bar'" 50 | ;; (LaTeX-mode) 51 | ;; (should (equal (sp-get-thing t) 52 | ;; '(:beg 16 :end 19 :op "" :cl "" :prefix "" :suffix ""))))) 53 | 54 | ;; #820 55 | (ert-deftest sp-test-LaTeX-do-not-fix-closing-delimiter-on-insert-when-inserting-more-than-one-char () 56 | "Some electric keys sometimes insert more than one character. 57 | In this case the behaviour is more complicated and we shouldn't 58 | try to fix the buffer. 59 | 60 | For example quote in LaTeX inserts two backticks which messes up 61 | with the search logic (if inserted one-by-one they would pair by 62 | thesmeves and would not break unrelated pair)" 63 | (sp-test-with-temp-buffer "quote: | $f' = 0$" 64 | (LaTeX-mode) 65 | (execute-kbd-macro "\"") 66 | (sp-buffer-equals "quote: ``|'' $f' = 0$"))) 67 | 68 | ;; #990 69 | (ert-deftest sp-test-LaTeX-do-parse-string-quotes-outside-math () 70 | (sp-test-with-temp-buffer "foo ``bar''| baz" 71 | (LaTeX-mode) 72 | (sp-backward-sexp) 73 | (sp-buffer-equals "foo |``bar'' baz"))) 74 | 75 | ;; #990 76 | (ert-deftest sp-test-LaTeX-dont-parse-string-quotes-in-math () 77 | (sp-test-with-temp-buffer "$foo ``bar''| baz$" 78 | (LaTeX-mode) 79 | (sp-backward-sexp) 80 | (sp-buffer-equals "$foo ``|bar'' baz$"))) 81 | 82 | ;; #990 83 | (ert-deftest sp-test-LaTeX-do-pair-string-quotes-outside-math () 84 | (sp-test-with-temp-buffer "foo | baz" 85 | (LaTeX-mode) 86 | (execute-kbd-macro "``") 87 | (sp-buffer-equals "foo ``|'' baz"))) 88 | 89 | ;; #990 90 | (ert-deftest sp-test-LaTeX-dont-pair-string-quotes-in-math () 91 | (sp-test-with-temp-buffer "$foo | baz$" 92 | (LaTeX-mode) 93 | (execute-kbd-macro "``") 94 | (sp-buffer-equals "$foo ``| baz$"))) 95 | 96 | ;; #834 97 | (ert-deftest sp-test-LaTeX-wrap-with-trigger () 98 | "A region should be wrapped with a pair if trigger key is pressed." 99 | (sp-test-with-temp-buffer "foo Mbar baz| bam" 100 | (LaTeX-mode) 101 | (execute-kbd-macro "\"") 102 | (sp-buffer-equals "foo ``bar baz''| bam"))) 103 | -------------------------------------------------------------------------------- /test/smartparens-tex-mode-latex-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-latex) 2 | 3 | (ert-deftest sp-test-latex-dont-insert-space-on-forward-slurp-where-not-necessary () 4 | (sp-test-with-temp-buffer "foo (|)(bar)(baz)" 5 | (latex-mode) 6 | (sp-forward-slurp-sexp 2) 7 | (sp-buffer-equals "foo (|(bar)(baz))") 8 | (sp-forward-barf-sexp 2) 9 | (sp-buffer-equals "foo (|)(bar)(baz)"))) 10 | 11 | (ert-deftest sp-test-latex-insert-space-on-forward-slurp-where-necessary () 12 | (sp-test-with-temp-buffer "foo (|bar)baz" 13 | (latex-mode) 14 | (sp-forward-slurp-sexp) 15 | (sp-buffer-equals "foo (|bar baz)") 16 | (sp-forward-barf-sexp) 17 | (sp-buffer-equals "foo (|bar) baz"))) 18 | 19 | (ert-deftest sp-test-latex-dont-insert-space-on-backward-slurp-where-not-necessary () 20 | (sp-test-with-temp-buffer "foo (bar)(baz)(|)" 21 | (latex-mode) 22 | (sp-backward-slurp-sexp 2) 23 | (sp-buffer-equals "foo ((bar)(baz)|)") 24 | (sp-backward-barf-sexp 2) 25 | (sp-buffer-equals "foo (bar)(baz)(|)"))) 26 | 27 | (ert-deftest sp-test-latex-insert-space-on-backward-slurp-where-necessary () 28 | (sp-test-with-temp-buffer "foo bar(baz|)" 29 | (latex-mode) 30 | (sp-backward-slurp-sexp) 31 | (sp-buffer-equals "foo (bar baz|)") 32 | (sp-backward-barf-sexp) 33 | (sp-buffer-equals "foo bar (baz|)"))) 34 | 35 | (ert-deftest sp-test-latex-navigate-single-quote-pair-backwards-at-opener () 36 | (sp-test-with-temp-buffer "\\foo{bar} `|foo bar'baz'" 37 | (latex-mode) 38 | (should (equal (sp-get-thing t) 39 | '(:beg 11 :end 24 :op "`" :cl "'" :prefix "" :suffix ""))))) 40 | 41 | (ert-deftest sp-test-latex-navigate-single-quote-pair-backwards-at-closer () 42 | (sp-test-with-temp-buffer "\\foo{bar} `foo bar'baz'|" 43 | (latex-mode) 44 | (should (equal (sp-get-thing t) 45 | '(:beg 11 :end 24 :op "`" :cl "'" :prefix "" :suffix ""))))) 46 | 47 | ;; SKIP: 48 | ;; (ert-deftest sp-test-latex-navigate-single-quote-pair-backwards-at-contraction () 49 | ;; (sp-test-with-temp-buffer "\\foo{bar} `foo bar'|bar'" 50 | ;; (latex-mode) 51 | ;; (should (equal (sp-get-thing t) 52 | ;; '(:beg 16 :end 19 :op "" :cl "" :prefix "" :suffix ""))))) 53 | 54 | ;; #820 55 | (ert-deftest sp-test-latex-do-not-fix-closing-delimiter-on-insert-when-inserting-more-than-one-char () 56 | "Some electric keys sometimes insert more than one character. 57 | In this case the behaviour is more complicated and we shouldn't 58 | try to fix the buffer. 59 | 60 | For example quote in latex inserts two backticks which messes up 61 | with the search logic (if inserted one-by-one they would pair by 62 | thesmeves and would not break unrelated pair)" 63 | (sp-test-with-temp-buffer "quote: | $f' = 0$" 64 | (latex-mode) 65 | (execute-kbd-macro "\"") 66 | (sp-buffer-equals "quote: ``|'' $f' = 0$"))) 67 | 68 | ;; #990 69 | (ert-deftest sp-test-latex-do-parse-string-quotes-outside-math () 70 | (sp-test-with-temp-buffer "foo ``bar''| baz" 71 | (latex-mode) 72 | (sp-backward-sexp) 73 | (sp-buffer-equals "foo |``bar'' baz"))) 74 | 75 | ;; #990 76 | (ert-deftest sp-test-latex-dont-parse-string-quotes-in-math () 77 | (sp-test-with-temp-buffer "$foo ``bar''| baz$" 78 | (latex-mode) 79 | (sp-backward-sexp) 80 | (sp-buffer-equals "$foo ``|bar'' baz$"))) 81 | 82 | ;; #990 83 | (ert-deftest sp-test-latex-do-pair-string-quotes-outside-math () 84 | (sp-test-with-temp-buffer "foo | baz" 85 | (latex-mode) 86 | (execute-kbd-macro "``") 87 | (sp-buffer-equals "foo ``|'' baz"))) 88 | 89 | ;; #990 90 | (ert-deftest sp-test-latex-dont-pair-string-quotes-in-math () 91 | (sp-test-with-temp-buffer "$foo | baz$" 92 | (latex-mode) 93 | (execute-kbd-macro "``") 94 | (sp-buffer-equals "$foo ``| baz$"))) 95 | 96 | ;; #834 97 | (ert-deftest sp-test-latex-wrap-with-trigger () 98 | "A region should be wrapped with a pair if trigger key is pressed." 99 | (sp-test-with-temp-buffer "foo Mbar baz| bam" 100 | (latex-mode) 101 | (execute-kbd-macro "\"") 102 | (sp-buffer-equals "foo ``bar baz''| bam"))) 103 | -------------------------------------------------------------------------------- /docs/automatic-escaping.rst: -------------------------------------------------------------------------------- 1 | Automatic escaping 2 | =============== 3 | 4 | Smartparens can automatically escape quote characters (``'``, ``"``) 5 | and the escape character ``\`` (as determined by Emacs's syntax 6 | tables) when you wrap a region or insert them inside a string. 7 | 8 | Autoescaping is specified on a per-pair basis. For convenience, there 9 | are two global options to enable or disable escaping after wrapping 10 | and after insertion of a pair. 11 | 12 | .. el:option:: sp-escape-wrapped-region 13 | 14 | If non-nil, escape special chars inside the just wrapped region. 15 | 16 | .. el:option:: sp-escape-quotes-after-insert 17 | 18 | If non-nil, escape string quotes if typed inside string. 19 | 20 | Escaping with post hooks 21 | ------------------------ 22 | 23 | To enable automatic escaping after wrapping or insertion it is 24 | necessary to add post-handlers on the pairs where you want to trigger 25 | the escaping. These are typically the ``"`` or ``'`` quote pairs. 26 | Escaping after wrapping is enabled by default. 27 | 28 | The hooks are named after the global options---if the option is 29 | disabled the function does nothing. 30 | 31 | .. el:function:: sp-escape-wrapped-region 32 | 33 | Escape quotes and special chars when a region is wrapped. 34 | 35 | The wrapping is smart in the sense that it only escapes when 36 | necessary. The behaviour of wrapping a word (``bar``) which is 37 | already inside a string is summarized by the following table: 38 | 39 | ==================== =================== =================== 40 | enclosing \\ wrapped ' " 41 | ==================== =================== =================== 42 | ' 'foo \\'bar\\' baz' 'foo "bar" baz' 43 | " "foo 'bar' baz" "foo \\"bar\\" baz" 44 | ==================== =================== =================== 45 | 46 | 47 | The behaviour of wrapping existing text (``foo 'bar' baz`` or ``foo 48 | "bar" baz``) containing a string is summarized by the following table: 49 | 50 | ===================== =================== =================== 51 | containing \\ wrapped ' " 52 | ===================== =================== =================== 53 | foo 'bar' baz 'foo \\'bar\\' baz' "foo 'bar' baz" 54 | foo "bar" baz 'foo "bar" baz' "foo \\"bar\\" baz" 55 | ===================== =================== =================== 56 | 57 | .. el:function:: sp-escape-quotes-after-insert 58 | 59 | Escape quotes inserted via `sp-insert-pair'. 60 | 61 | If auto-pairing is enabled and the pair was successfully inserted 62 | inside a string, this hook ensures that it is escaped properly if 63 | necessary. The same rules as for wrapping apply, that is, escaping 64 | only takes place when necessary. This hook is triggered on the 65 | ``'insert`` action, and so if a ``:when`` or ``:unless`` handler 66 | prevents pairing, no action is taken. 67 | 68 | 69 | Escape action 70 | ------------- 71 | 72 | Some users prefer not to pair quotes inside strings and instead only 73 | insert the single delimiter (this is the paredit behaviour). However, 74 | if the user disabled auto-pairing inside strings, that means the 75 | ``sp-escape-quotes-after-insert`` handler is never called and the 76 | quote will get inserted unescaped. 77 | 78 | This situation can be handled by adding an ``'escape`` action on the 79 | pair. That tells smartparens to still escape the single inserted 80 | delimiter even if the insert action wasn't performed. 81 | 82 | Having a separate action might seem extraneous, but it gives us better 83 | flexibility in defining the escaping rules to precisely match what is 84 | expected. Also, by the nature of the post-handlers, which are only 85 | run after the action is performed successfully, it is necessary to 86 | have an action separate from ``'insert`` which might get inhibited by 87 | other predicates. 88 | 89 | As usual, actions are tried in sequence: ``'wrap``, ``'insert``, 90 | ``'escape``, so if the pair is wrapped or inserted the escape action 91 | is skipped (and the escaping can be handled with the handlers from 92 | previous section). 93 | 94 | The single-pair behaviour is summarized in the following table: 95 | 96 | ===================== =================== =================== 97 | enclosing \\ inserted ' " 98 | ===================== =================== =================== 99 | 'foo | bar' 'foo \\'| bar' 'foo "| bar' 100 | "foo | bar" "foo '| bar" "foo \\"| bar" 101 | ===================== =================== =================== 102 | -------------------------------------------------------------------------------- /test/smartparens-framework-test.el: -------------------------------------------------------------------------------- 1 | ;; Tests which don't fit anywhere else 2 | 3 | (ert-deftest sp-test-sp-point-in-symbol-at-the-eob () 4 | "When the point is `eobp' it should not be in symbol." 5 | (sp-test-with-temp-elisp-buffer "foo-bar|" 6 | (should (not (sp-point-in-symbol))))) 7 | 8 | (ert-deftest sp-test-sp-point-in-comment-inside-string () 9 | (sp-test-with-temp-elisp-buffer "\"foo |;foo-bar\"" 10 | (should-not (sp-point-in-comment)))) 11 | 12 | (ert-deftest sp-test-sp-point-in-symbol-inside-symbol () 13 | "When the point is inside symbol it should be in symbol." 14 | (sp-test-with-temp-elisp-buffer "foo-|bar" 15 | (should (sp-point-in-symbol))) 16 | (sp-test-with-temp-elisp-buffer "foo-b|ar" 17 | (should (sp-point-in-symbol)))) 18 | 19 | ;; #634 20 | (ert-deftest sp-test-sp-skip-backward-to-symbol-sexp-at-the-end-of-comment () 21 | "When we are skipping backward and land on a sexp delimiter 22 | right at the end of comment, and we started outside a comment, we 23 | should skip the current comment instead of ending on the 24 | delimiter." 25 | (sp-test-with-temp-elisp-buffer "foo\n;; (bar)\n|baz" 26 | (sp-skip-backward-to-symbol) 27 | (insert "|") 28 | (should (equal (buffer-string) "foo|\n;; (bar)\nbaz"))) 29 | 30 | (sp-test-with-temp-elisp-buffer "foo\n;; \"bar\"\n|baz" 31 | (sp-skip-backward-to-symbol) 32 | (insert "|") 33 | (should (equal (buffer-string) "foo|\n;; \"bar\"\nbaz")))) 34 | 35 | (ert-deftest sp-test-sp-skip-backward-to-symbol-reset-prefix () 36 | "If the first skip was a prefix skip, we need to reset the 37 | prefix after jumping over it, otherwise each successive skip 38 | would move (length prefix) characters" 39 | (let ((sp-sexp-prefix '((emacs-lisp-mode regexp "\\(?:aaa\\)")))) 40 | (sp-test-with-temp-elisp-buffer "foo bar aaa|(baz)" 41 | (sp-skip-backward-to-symbol) 42 | (sp-buffer-equals "foo bar| aaa(baz)")))) 43 | 44 | (ert-deftest sp-test-looking-back () 45 | (sp-test-with-temp-elisp-buffer "foo \\|\\ bar" 46 | (should (sp--looking-back "\\\\+")) 47 | (should (eq (match-end 0) 6))) 48 | 49 | (sp-test-with-temp-elisp-buffer "OPEN|CLOSE" 50 | (should (not (sp--looking-back "OPEN\\>")))) 51 | 52 | (sp-test-with-temp-elisp-buffer "OPEN| CLOSE" 53 | (should (sp--looking-back "OPEN\\>")) 54 | (should (eq (match-end 0) 5)))) 55 | 56 | (ert-deftest sp-test-char-is-escaped-p () 57 | (sp-test-with-temp-elisp-buffer "\\|t" 58 | (should (sp-char-is-escaped-p))) 59 | 60 | (sp-test-with-temp-elisp-buffer "\\\\|t" 61 | (should (not (sp-char-is-escaped-p)))) 62 | 63 | (sp-test-with-temp-elisp-buffer "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|t" 64 | (should (sp-char-is-escaped-p))) 65 | 66 | (sp-test-with-temp-elisp-buffer "\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\|t" 67 | (should (not (sp-char-is-escaped-p)))) 68 | 69 | (sp-test-with-temp-elisp-buffer "\\\\|" 70 | (should (not (sp-char-is-escaped-p)))) 71 | 72 | (sp-test-with-temp-elisp-buffer "\"foo bar \\\"| baz\"" 73 | (should (sp-char-is-escaped-p (1- (point)))))) 74 | 75 | (ert-deftest sp-test-sp--strict-regexp-opt-no-strings () 76 | "`sp--strict-regexp-opt' on nil input should return unmatchable regexp. 77 | 78 | This is not consistent with `regexp-opt' which returns empty string." 79 | (should (equal "^\\<$" (sp--strict-regexp-opt nil)))) 80 | 81 | (ert-deftest sp-test-sp--get-stringlike-regexp-with-delimiter () 82 | "In case there are string-like delimiters we should return a 83 | regexp that matches them." 84 | (let ((sp-pairs '((t . ((:open "\"" :close "\"" :actions (insert wrap autoskip navigate))))))) 85 | (sp-test-with-temp-elisp-buffer "foo |\"bar\"" 86 | (should (sp--looking-at-p (sp--get-stringlike-regexp)))) 87 | (sp-test-with-temp-elisp-buffer "\"bar\"| baz" 88 | (should (sp--looking-back-p (sp--get-stringlike-regexp)))))) 89 | 90 | (ert-deftest sp-test-sp--get-stringlike-regexp-with-no-delimiter () 91 | "In case there is no string-like delimiter we should return a 92 | regexp that never matches anything." 93 | (let ((sp-pairs '((t . ((:open "(" :close ")" :actions (insert wrap autoskip navigate))))))) 94 | (sp-test-with-temp-elisp-buffer "foo |\"bar\"" 95 | (should-not (sp--looking-at-p (sp--get-stringlike-regexp)))) 96 | (sp-test-with-temp-elisp-buffer "\"bar\"| baz" 97 | (should-not (sp--looking-back-p (sp--get-stringlike-regexp)))) 98 | (sp-test-with-temp-elisp-buffer "foo |(bar)" 99 | (should-not (sp--looking-at-p (sp--get-stringlike-regexp)))) 100 | (sp-test-with-temp-elisp-buffer "(bar)| baz" 101 | (should-not (sp--looking-back-p (sp--get-stringlike-regexp)))))) 102 | -------------------------------------------------------------------------------- /test/smartparens-skip-closing-pair-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | 3 | (ert-deftest sp-test-buffer-modified-sp-skip-closing-pair () 4 | "Test the correct setting of `buffer-modified-p' flag after 5 | executing `sp-skip-closing-pair'." 6 | (with-temp-buffer 7 | (insert "foobar") 8 | (should (eq (buffer-modified-p) t)) 9 | (goto-char (point-min)) 10 | (insert "(") 11 | (goto-char (point-max)) 12 | (insert ")") 13 | (backward-char 1) 14 | (sp-skip-closing-pair ")") 15 | (should (eq (buffer-modified-p) t)) 16 | (backward-char 1) 17 | (set-buffer-modified-p nil) 18 | (sp-skip-closing-pair ")") 19 | (should (eq (buffer-modified-p) nil)) 20 | (let ((sp-autoskip-closing-pair 'always)) 21 | (goto-char 3) 22 | (sp-skip-closing-pair ")") 23 | (should (eq (buffer-modified-p) nil)) 24 | (goto-char 3) 25 | (insert "a") 26 | (sp-skip-closing-pair ")") 27 | (should (eq (buffer-modified-p) t))))) 28 | 29 | (ert-deftest sp-test-escaped-pair-is-not-skipped-in-string () 30 | (sp-test-with-temp-elisp-buffer "\"\\|\"" 31 | (execute-kbd-macro "\"") 32 | (insert "|") 33 | (should (equal (buffer-string) "\"\\\"|\\\"\"")))) 34 | 35 | (ert-deftest sp-test-non-escaped-pair-is-skipped-in-string () 36 | (sp-test-with-temp-elisp-buffer "\"\\t foo | bar\"" 37 | (execute-kbd-macro "[]") 38 | (insert "|") 39 | (should (equal (buffer-string) "\"\\t foo []| bar\"")))) 40 | 41 | (ert-deftest sp-test-non-escaped-pair-is-skipped-in-string-c++ () 42 | (sp-test-with-temp-buffer "std::string a = \"foo\\nbar\";\n\"|\";" 43 | (c++-mode) 44 | (execute-kbd-macro "[]|") 45 | (should (equal (buffer-string) "std::string a = \"foo\\nbar\";\n\"[]|\";")))) 46 | 47 | (ert-deftest sp-test-non-escaped-pair-is-skipped-in-string-python () 48 | (sp-test-with-temp-buffer "from sys import stdin, \\\n stdout\n\na = \"|\"" 49 | (c++-mode) 50 | (execute-kbd-macro "[]|") 51 | (should (equal (buffer-string) "from sys import stdin, \\\n stdout\n\na = \"[]|\"")))) 52 | 53 | ;; #778 54 | (ert-deftest sp-test-reindent-after-skip-closing-pair-in-strict-mode () 55 | (sp-test-with-temp-elisp-buffer "(foo\n | \n)" 56 | (smartparens-strict-mode 1) 57 | (execute-kbd-macro ")") 58 | (sp-buffer-equals "(foo)|"))) 59 | 60 | ;; #778 61 | (ert-deftest sp-test-reindent-after-skip-closing-pair-with-autoskip-disabled () 62 | (sp-test-with-temp-elisp-buffer "(foo\n | \n)" 63 | (let ((sp-autoskip-closing-pair nil)) 64 | (execute-kbd-macro ")") 65 | (sp-buffer-equals "(foo\n )| \n)")))) 66 | 67 | ;; #421 68 | ;; If we are in a balanced context and hit a closing delimiter for 69 | ;; an autoskip pair which is not enclosing (so we would jump out of 70 | ;; the sexp) we should not insert it as it would just create an 71 | ;; imbalance. 72 | (ert-deftest sp-test-strict-mode-inhibit-closing-delim-inside-sexp () 73 | (sp-test-with-temp-elisp-buffer "(foo | bar)" 74 | (smartparens-strict-mode 1) 75 | (execute-kbd-macro "]") 76 | (sp-buffer-equals "(foo | bar)"))) 77 | 78 | ;; However, if the pair is not autoskip, then we insert the closing 79 | ;; delimiter when typed, regardless of balance context. 80 | (ert-deftest sp-test-strict-mode-dont-inhibit-closing-non-autoskip-delim () 81 | (sp-test-with-temp-buffer "" nil 82 | (let ((sp-pairs sp-pairs)) 83 | (smartparens-strict-mode) 84 | (sp-local-pair major-mode "{" "}" :actions '(insert autoskip navigate wrap)) 85 | (execute-kbd-macro "}") 86 | (should (eq (char-before) nil)) 87 | (sp-local-pair major-mode "{" "}" :actions '(:rem autoskip)) 88 | (execute-kbd-macro "}") 89 | (should (eq (char-before) ?\}))))) 90 | 91 | (ert-deftest sp-test-strict-mode-inhibit-closing-delim-outside-sexp () 92 | (sp-test-with-temp-elisp-buffer "(foo bar) | (bar baz)" 93 | (smartparens-strict-mode 1) 94 | (execute-kbd-macro "]") 95 | (sp-buffer-equals "(foo bar) | (bar baz)"))) 96 | 97 | (ert-deftest sp-test-strict-mode-insert-closing-delim-in-comment () 98 | (sp-test-with-temp-elisp-buffer ";; (foo bar) | (bar baz)" 99 | (smartparens-strict-mode 1) 100 | (execute-kbd-macro "]") 101 | (sp-buffer-equals ";; (foo bar) ]| (bar baz)"))) 102 | 103 | (ert-deftest sp-test-strict-mode-insert-disallowed-pairs-normally () 104 | (sp-test-with-temp-elisp-buffer ";; (foo bar) |foo (bar baz)" 105 | (smartparens-strict-mode 1) 106 | (execute-kbd-macro "'") 107 | (sp-buffer-equals ";; (foo bar) '|foo (bar baz)"))) 108 | 109 | (ert-deftest sp-test-non-strict-mode-insert-closing-delim () 110 | "In non-strict mode, just insert whatever" 111 | (sp-test-with-temp-elisp-buffer "(foo | bar)" 112 | (execute-kbd-macro "]") 113 | (sp-buffer-equals "(foo ]| bar)"))) 114 | -------------------------------------------------------------------------------- /test/smartparens-delete-selection-test.el: -------------------------------------------------------------------------------- 1 | ;; Tests for delete-selection-mode and strict mode integration 2 | 3 | (defmacro sp-test-delsel (initial &rest forms) 4 | (declare (indent 1)) 5 | `(sp-test-with-delete-selection-mode 6 | (sp-test-with-temp-elisp-buffer ,initial 7 | (smartparens-strict-mode 1) 8 | ,@forms))) 9 | 10 | ;; Overwriting with letters 11 | (ert-deftest sp-test-delete-selection-mode-self-insert-can-not-kill-invalid-region () 12 | (sp-test-delsel "(fo|o) bMar" 13 | (execute-kbd-macro "x") 14 | (sp-buffer-equals "(fo|o) bMar"))) 15 | 16 | (ert-deftest sp-test-delete-selection-mode-self-insert-can-kill-valid-region () 17 | (sp-test-delsel "(fo|o bMar)" 18 | (execute-kbd-macro "x") 19 | (sp-buffer-equals "(fox|ar)"))) 20 | 21 | (ert-deftest sp-test-delete-selection-mode-nonstrict-self-insert-can-kill-invalid-region () 22 | (sp-test-delsel "(fo|o) bMar" 23 | (smartparens-strict-mode -1) 24 | (execute-kbd-macro "x") 25 | (sp-buffer-equals "(fox|ar"))) 26 | 27 | (ert-deftest sp-test-delete-selection-mode-nonstrict-self-insert-can-kill-valid-region () 28 | (sp-test-delsel "(fo|o bMar)" 29 | (smartparens-strict-mode -1) 30 | (execute-kbd-macro "x") 31 | (sp-buffer-equals "(fox|ar)"))) 32 | 33 | ;; Calling sp-delete-char 34 | (ert-deftest sp-test-delete-selection-mode-delete-char-can-not-kill-invalid-region () 35 | (sp-test-delsel "(fo|o) bMar" 36 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 37 | (execute-kbd-macro "d")) 38 | (sp-buffer-equals "(fo|o) bMar"))) 39 | 40 | (ert-deftest sp-test-delete-selection-mode-delete-char-can-kill-valid-region () 41 | (sp-test-delsel "(fo|o bMar)" 42 | (sp-test-with-temp-binding ("d" 'sp-delete-char) 43 | (execute-kbd-macro "d")) 44 | (sp-buffer-equals "(fo|ar)"))) 45 | 46 | (ert-deftest sp-test-delete-selection-mode-nonstrict-delete-char-can-kill-invalid-region () 47 | (sp-test-delsel "(fo|o) bMar" 48 | (smartparens-strict-mode -1) 49 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 50 | (execute-kbd-macro "d")) 51 | (sp-buffer-equals "(fo|ar"))) 52 | 53 | (ert-deftest sp-test-delete-selection-mode-nonstrict-delete-char-can-kill-valid-region () 54 | (sp-test-delsel "(fo|o bMar)" 55 | (smartparens-strict-mode -1) 56 | (sp-test-with-temp-binding ("d" 'sp-delete-char) 57 | (execute-kbd-macro "d")) 58 | (sp-buffer-equals "(fo|ar)"))) 59 | 60 | ;; Calling sp-backward-delete-char 61 | (ert-deftest sp-test-delete-selection-mode-backward-delete-char-can-not-kill-invalid-region () 62 | (sp-test-delsel "(fo|o) bMar" 63 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 64 | (execute-kbd-macro "d")) 65 | (sp-buffer-equals "(fo|o) bMar"))) 66 | 67 | (ert-deftest sp-test-delete-selection-mode-backward-delete-char-can-kill-valid-region () 68 | (sp-test-delsel "(fo|o bMar)" 69 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 70 | (execute-kbd-macro "d")) 71 | (sp-buffer-equals "(fo|ar)"))) 72 | 73 | (ert-deftest sp-test-delete-selection-mode-nonstrict-backward-delete-char-can-kill-invalid-region () 74 | (sp-test-delsel "(fo|o) bMar" 75 | (smartparens-strict-mode -1) 76 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 77 | (execute-kbd-macro "d")) 78 | (sp-buffer-equals "(fo|ar"))) 79 | 80 | (ert-deftest sp-test-delete-selection-mode-nonstrict-backward-delete-char-can-kill-valid-region () 81 | (sp-test-delsel "(fo|o bMar)" 82 | (smartparens-strict-mode -1) 83 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 84 | (execute-kbd-macro "d")) 85 | (sp-buffer-equals "(fo|ar)"))) 86 | 87 | ;; #703 88 | (ert-deftest sp-test-delete-selection-mode/empty-sexp/point-before-mark () 89 | (sp-test-delsel "(| 90 | 91 | M)" 92 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 93 | (execute-kbd-macro "d")) 94 | (sp-buffer-equals "(|M)"))) 95 | 96 | (ert-deftest sp-test-delete-selection-mode/empty-sexp/point-after-mark () 97 | (sp-test-delsel "(M 98 | 99 | |)" 100 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 101 | (execute-kbd-macro "d")) 102 | (sp-buffer-equals "(M|)"))) 103 | 104 | (ert-deftest sp-test-delete-selection-mode/nonstrict/empty-sexp/point-before-mark () 105 | (sp-test-delsel "(| 106 | 107 | M)" 108 | (smartparens-strict-mode -1) 109 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 110 | (execute-kbd-macro "d")) 111 | (sp-buffer-equals "(|M)"))) 112 | 113 | (ert-deftest sp-test-delete-selection-mode/nonstrict/empty-sexp/point-after-mark () 114 | (sp-test-delsel "(M 115 | 116 | |)" 117 | (smartparens-strict-mode -1) 118 | (sp-test-with-temp-binding ("d" 'sp-backward-delete-char) 119 | (execute-kbd-macro "d")) 120 | (sp-buffer-equals "(M|)"))) 121 | -------------------------------------------------------------------------------- /smartparens-swift.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-swift.el --- Additional configuration for Swift language buffers. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015 Wilfred Hughes, 4 | ;; 2022 Josh Caswell 5 | 6 | ;; Created: 4 April 2022 7 | ;; Keywords: abbrev convenience editing 8 | ;; URL: https://github.com/Fuco1/smartparens 9 | 10 | ;; This file is not part of GNU Emacs. 11 | 12 | ;;; License: 13 | 14 | ;; This file is part of Smartparens. 15 | 16 | ;; Smartparens is free software; you can redistribute it and/or modify 17 | ;; it under the terms of the GNU General Public License as published by 18 | ;; the Free Software Foundation, either version 3 of the License, or 19 | ;; (at your option) any later version. 20 | 21 | ;; Smartparens is distributed in the hope that it will be useful, 22 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | ;; GNU General Public License for more details. 25 | 26 | ;; You should have received a copy of the GNU General Public License 27 | ;; along with Smartparens. If not, see . 28 | 29 | ;;; Commentary: 30 | 31 | ;; This file provides some additional configuration for Swift. To use it in 32 | ;; conjunction with either `swift-mode' or `swift-ts-mode', simply add: 33 | ;; 34 | ;; (require 'smartparens-config) 35 | ;; 36 | ;; alternatively, you can explicitly load these preferences: 37 | ;; 38 | ;; (require 'smartparens-swift) 39 | ;; 40 | ;; in your configuration. 41 | 42 | ;; For more info, see github readme at 43 | ;; https://github.com/Fuco1/smartparens 44 | 45 | ;;; Code: 46 | (require 'smartparens) 47 | 48 | (declare-function swift-mode "swift-mode") 49 | (declare-function swift-ts-mode "swift-ts-mode") 50 | 51 | (defun sp-swift-skip-match-angle-bracket (_ms _mb me) 52 | "Non-nil if we should ignore the bracket as valid delimiter." 53 | (save-excursion 54 | (goto-char me) 55 | (let ((on-fn-return-type 56 | (sp--looking-back-p (rx "->") nil)) 57 | (on-range-operator 58 | (sp--looking-back-p (rx "..<") nil)) 59 | (on-comparison 60 | (sp--looking-back-p (rx (or 61 | (seq space "<") 62 | (seq space ">") 63 | (seq space "<<") 64 | (seq space ">>"))) 65 | nil))) 66 | (or on-comparison on-fn-return-type on-range-operator)))) 67 | 68 | (defun sp-swift-filter-angle-brackets (_id action context) 69 | "Non-nil if we should allow ID's ACTION in CONTEXT for angle brackets." 70 | ;; See the docstring for `sp-pair' for the possible values of ID, 71 | ;; ACTION and CONTEXT. 72 | (cond 73 | ;; Inside strings, don't do anything with < or >. 74 | ((eq context 'string) 75 | nil) 76 | ((or (eq context 'comment) 77 | (eq context 'code)) 78 | (let ((on-fn-return-type 79 | (looking-back (rx "->") nil)) 80 | (on-range-operator 81 | (looking-back (rx "..<") nil)) 82 | (on-comparison 83 | (looking-back (rx (or 84 | (seq space "<") 85 | (seq space ">") 86 | (seq space "<<") 87 | (seq space ">>"))) 88 | nil))) 89 | (cond 90 | ;; Only insert a matching > if we're not looking at one of the operators. 91 | ((eq action 'insert) 92 | (and (not on-comparison) (not on-fn-return-type) (not on-range-operator))) 93 | ;; Allow wrapping in a pair if the region is active and we're not on a 94 | ;; range operator. 95 | ((eq action 'wrap) 96 | (not on-range-operator)) 97 | ;; When pressing >, autoskip if we're not looking at one of the 98 | ;; operators. 99 | ((eq action 'autoskip) 100 | (and (not on-comparison) (not on-fn-return-type) (not on-range-operator))) 101 | ;; Allow navigation, highlighting and strictness checks if it's 102 | ;; not one of the operators. 103 | ((eq action 'navigate) 104 | (and (not on-comparison) (not on-fn-return-type) (not on-range-operator)))))))) 105 | 106 | (sp-with-modes '(swift-mode swift-ts-mode) 107 | (sp-local-pair "<" ">" 108 | :when '(sp-swift-filter-angle-brackets) 109 | :skip-match 'sp-swift-skip-match-angle-bracket) 110 | (sp-local-pair "\"\"\"" "\"\"\"") 111 | (sp-local-pair "\\(" ")" :actions '(wrap insert) :when '(sp-in-string-p))) 112 | 113 | ;; Swift has no sexp suffixes. This fixes slurping 114 | ;; (|foo).bar -> (foo.bar) 115 | (dolist (mode '(swift-mode swift-ts-mode)) 116 | (add-to-list 'sp-sexp-suffix (list mode 'regexp ""))) 117 | 118 | (provide 'smartparens-swift) 119 | 120 | ;;; smartparens-swift.el ends here 121 | -------------------------------------------------------------------------------- /smartparens-haskell.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-haskell.el --- Additional configuration for Haskell based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015, 2017-2018 Michael Xavier, Matus Goljer 4 | 5 | ;; Author: Michael Xavier 6 | ;; Maintainer: Michael Xavier 7 | ;; Created: 29 Apr 2016 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Haskell based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-haskell) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | (require 'smartparens) 48 | 49 | (defun sp-haskell-skip-apostrophe (_ms mb _me) 50 | (save-excursion 51 | ;; We test the syntax class because haskell mode overrides 52 | ;; the class for ' on the fly when it run the syntax pass of 53 | ;; font-lock... so that if '' is a valid string (char) it 54 | ;; gets an override via 'syntax-table property. In which 55 | ;; case we just agree with haskell mode and let it be used as 56 | ;; a pair. 57 | (not (eq (syntax-class (syntax-after mb)) 7)))) 58 | 59 | (defun sp-haskell-strict-ignore-apostrophe-after-word (_id action _context) 60 | "Ignore trailing ' when navigating. 61 | 62 | Because ' in haskell is symbol class it gets picked up as part of 63 | a words such as myFunction', and then strict mode won't allow us 64 | to delete it. Also show-smartparens-mode incorrectly highlights 65 | it as missing an opener. 66 | 67 | So we ignore that pair when at the end of word." 68 | (when (eq action 'navigate) 69 | (sp--looking-back-p (concat "\\(\\sw\\|\\s_\\)'+")))) 70 | 71 | (sp-with-modes '(haskell-mode haskell-interactive-mode) 72 | (sp-local-pair "{-" "-}") 73 | (sp-local-pair "{-#" "#-}") 74 | (sp-local-pair "{-@" "@-}") 75 | (sp-local-pair "'" nil 76 | :unless '(sp-point-after-word-p 77 | sp-haskell-strict-ignore-apostrophe-after-word) 78 | :skip-match 'sp-haskell-skip-apostrophe) 79 | (sp-local-pair "\\(" nil :actions nil)) 80 | 81 | (defun sp--inferior-haskell-mode-backward-bound-fn () 82 | "Limit the backward search to the prompt if point is on prompt." 83 | (-when-let (limit (cond ((bound-and-true-p comint-last-prompt) 84 | (marker-position (cdr comint-last-prompt))) 85 | ((bound-and-true-p comint-last-prompt-overlay) 86 | (overlay-end comint-last-prompt-overlay)) 87 | (t nil))) 88 | (and (> (point) limit) limit))) 89 | 90 | (defun sp--inferior-haskell-mode-forward-bound-fn () 91 | "Limit the forward search to exclude the prompt if point is before prompt." 92 | (-when-let (limit (cond ((bound-and-true-p comint-last-prompt) 93 | (marker-position (car comint-last-prompt))) 94 | ((bound-and-true-p comint-last-prompt-overlay) 95 | (overlay-start comint-last-prompt-overlay)) 96 | (t nil))) 97 | (and (< (point) limit) limit))) 98 | 99 | (defun sp--setup-inferior-haskell-mode-search-bounds () 100 | "Setup the search bound. 101 | 102 | If the point is after the last prompt, limit the backward search 103 | only for the propmt. 104 | 105 | If the point is before the last prompt, limit the forward search up until the prompt start." 106 | (setq sp-forward-bound-fn 'sp--inferior-haskell-mode-forward-bound-fn) 107 | (setq sp-backward-bound-fn 'sp--inferior-haskell-mode-backward-bound-fn)) 108 | 109 | (add-hook 'inferior-haskell-mode-hook 'sp--setup-inferior-haskell-mode-search-bounds) 110 | 111 | (provide 'smartparens-haskell) 112 | 113 | ;;; smartparens-haskell.el ends here 114 | -------------------------------------------------------------------------------- /test/smartparens-swift-test.el: -------------------------------------------------------------------------------- 1 | (require 'swift-mode) 2 | (require 'smartparens) 3 | 4 | (ert-deftest sp-test-swift-kill-first-line () 5 | "Ensure we can kill words on the first line. 6 | Regression test." 7 | (sp-test-with-temp-buffer "extern|" 8 | (swift-mode) 9 | (sp-backward-kill-word 1) 10 | (should (equal (buffer-string) "")))) 11 | 12 | (ert-deftest sp-test-swift-pair-angle-bracket () 13 | "When typing < we should insert the matching pair 14 | \(when appropriate\)." 15 | (sp-test-with-temp-buffer "Result|" 16 | (swift-mode) 17 | (execute-kbd-macro "<") 18 | ;; We should have inserted a pair. 19 | (should (equal (buffer-string) "Result<>")))) 20 | 21 | (ert-deftest sp-test-swift-forward-angle-bracket () 22 | "< and > are usually brackets in Swift." 23 | (sp-test-with-temp-buffer "struct Foo { 24 | baz: Baz| 25 | }" 26 | (swift-mode) 27 | (sp-forward-sexp) 28 | ;; We should have moved over the closing >. 29 | (should (looking-at "\n")))) 30 | 31 | (ert-deftest sp-test-swift-less-than () 32 | "When using < to compare, don't insert >." 33 | (sp-test-with-temp-buffer "if x |" 34 | (swift-mode) 35 | (execute-kbd-macro "<") 36 | (should (equal (buffer-string) "if x <")))) 37 | 38 | (ert-deftest sp-test-swift-left-shift () 39 | "When using << for a left shift, don't insert >." 40 | (sp-test-with-temp-buffer "if x <|" 41 | (swift-mode) 42 | (execute-kbd-macro "<") 43 | (should (equal (buffer-string) "if x <<")))) 44 | 45 | (ert-deftest sp-test-swift-left-shift-then-function () 46 | "We should still be able to insert -> after a left shift." 47 | (sp-test-with-temp-buffer "let y: UInt64 = 1 << 2; 48 | 49 | func foo(x: UInt64) -| 50 | 51 | func bar(x: UInt64) -> Bool { 52 | true 53 | } 54 | " 55 | (swift-mode) 56 | (smartparens-strict-mode) 57 | (execute-kbd-macro ">") 58 | (should (equal (buffer-substring (line-beginning-position) (line-end-position)) 59 | "func foo(x: UInt64) ->")))) 60 | 61 | (ert-deftest sp-test-swift-delete-comparison () 62 | "We should be able to delete comparisons, even in strict mode." 63 | (sp-test-with-temp-buffer "a < b; b >|" 64 | (swift-mode) 65 | (smartparens-strict-mode) 66 | (execute-kbd-macro (kbd "")) 67 | (should (equal (buffer-string) "a < b; b ")))) 68 | 69 | (ert-deftest sp-test-swift-pair-angle-bracket-in-constructor-call () 70 | "Pair < when parameterizing constructor calls." 71 | (sp-test-with-temp-buffer "Array|" 72 | (swift-mode) 73 | (execute-kbd-macro "<") 74 | ;; We should have inserted a pair. 75 | (should (equal (buffer-string) "Array<>")))) 76 | 77 | (ert-deftest sp-test-swift-pair-autoskip-closing-bracket () 78 | "Autoskip a matching >." 79 | (sp-test-with-temp-buffer "Array" 80 | (swift-mode) 81 | (execute-kbd-macro ">") 82 | ;; We should have skipped the closing bracket. 83 | (should (equal (buffer-string) "Array")))) 84 | 85 | (ert-deftest sp-test-swift-pair-insert-and-autoskip-closing-bracket () 86 | "Inserting multiple > and closing them." 87 | (sp-test-with-temp-buffer "Optional|" 88 | (swift-mode) 89 | (execute-kbd-macro ">>") 90 | ;; We should have inserted a pair without an extra chevron. 91 | (should (equal (buffer-string) "Optional>>")))) 92 | 93 | (ert-deftest sp-test-swift-insert-range-operator () 94 | "Inserting a range operator." 95 | (sp-test-with-temp-buffer "foo..|" 96 | (swift-mode) 97 | (execute-kbd-macro " UInt32" 104 | (swift-mode) 105 | (sp-forward-sexp) 106 | (execute-kbd-macro "{") 107 | (sp-buffer-equals "func foo() -> UInt32{|}"))) 108 | 109 | ;; #793 110 | (ert-deftest sp-test-swift-skip-backward-over-return-type () 111 | "Moving backward over a function's return type." 112 | (sp-test-with-temp-buffer "foo() -> |UInt32 {}" 113 | (swift-mode) 114 | (smartparens-strict-mode 1) 115 | (sp-backward-sexp) 116 | (sp-buffer-equals "foo|() -> UInt32 {}"))) 117 | 118 | ;; #793 119 | (ert-deftest sp-test-swift-kill-defun () 120 | "Deleting a region containing a Swift function definition." 121 | (sp-test-with-temp-buffer "|func foo() ->UInt32 {}" 122 | (swift-mode) 123 | (mark-whole-buffer) 124 | (call-interactively 'sp-kill-region) 125 | (should (equal (buffer-string) "")))) 126 | 127 | (ert-deftest sp-test-swift-string-interp-paren () 128 | "String interpolation should not escape closing paren" 129 | (sp-test-with-temp-buffer "print(\"foo is: |\")" 130 | (swift-mode) 131 | (execute-kbd-macro "\\(") 132 | (sp-buffer-equals "print(\"foo is: \\(|)\")"))) 133 | -------------------------------------------------------------------------------- /dev/_old/parser-system.org: -------------------------------------------------------------------------------- 1 | This file outlines the new "parser" system that's going to gradually replace the old (albeit somewhat working) mess. If you want to help, feel free to ask for work :) 2 | 3 | * General idea of getting things 4 | 1. figure out what context we're operating in, set the search bounds if necessary. 5 | 2. skip to opening or closing end of thing. 6 | 3. do this for all the "thing types" and then pick the closest one to actually carry out the search. Note that the search direction can reverse if we land on closing delimiter first. 7 | 4. return the data about the thing. Make data about conflicting things available somehow (e.g. sgml tag pair and the <> pair opening it). 8 | 9 | Every function should have a name =sp-get-$foo= with single optional argument =back= that tells sp to search backward. Each should in turn call a helper function =sp--get-$foo= which should support these arguments (when reasonable): 10 | - back 11 | - bound: limit for the search 12 | - context: where are we searching, see the next section. We should be able to provide a context we want or use the "current one". If some is provided, we should first find such context and go there, then set up bounds etc. 13 | 14 | The reason for this split is to provide a nicer interface for querying: when we want to query thing at point, we *don't* want to bother with search limits or contexts etc. 15 | 16 | The return value should be a plist with these attributes: 17 | 18 | #+BEGIN_EXAMPLE 19 | - :beg - point in buffer where the opening delimiter starts 20 | - :end - point in buffer where the closing delimiter ends 21 | - :op - opening delimiter or "" if there is none (e.g. for symbols) 22 | - :cl - closing delimiter 23 | - :prefix - thing prefix (e.g. ' in lisp) 24 | - :suffix - thing suffix 25 | - :from - point from which the search was started. This helps us to get the "things inbetween" point and sexp 26 | #+END_EXAMPLE 27 | 28 | This data structure should be usable with =sp-get= macro. 29 | 30 | In addition, there should be these functions for each $foo: 31 | 32 | ** sp-skip-to-$foo 33 | This should accept direction, search limits and context. The return value should be: 34 | 35 | #+BEGIN_EXAMPLE 36 | - :point - point, is equal to :ms or :me depending on direction 37 | - :mb - point where the thing starts (match-beginning) 38 | - :me - point where the thing ends (match-end) 39 | - :skipped - the distance travelled. Is negative if search was backward 40 | - :back - t if backward search, nil if forward search 41 | - :delim - the delimiter found 42 | #+END_EXAMPLE 43 | 44 | This function should ignore prefix or suffix. 45 | 46 | * Special contexts we need to consider 47 | We should write functions that will: 48 | - =sp-skip-to-context= skip into specified context 49 | - =sp-skip-outof-context= skip outof specified context 50 | - =sp-get-context= find the type of current context 51 | - =sp-get-context-info= find type and bounds of current context 52 | 53 | These should be general enough to be useful on their own as well as in =sp-get-$foo= functions to limit the searches. In general, every "getter" function where it makes sense should support all of these, so that the behaviour will be as consistent as possible. 54 | 55 | The return value for =sp-get-context-info= is a list with properties: 56 | 57 | #+BEGIN_EXAMPLE 58 | - :type - type of context 59 | - :beg - start of the context 60 | - :end - end of the context 61 | #+END_EXAMPLE 62 | 63 | ** strings 64 | We should limit the search to the string bounds. For now, only strings supported by syntax tables should be considered 65 | 66 | ** comments 67 | There are two options: 68 | - we can only search in current comment block 69 | - we can do "invert search", that is ignore code and only search comments. This can be useful to pair things like @{: 70 | 71 | #+BEGIN_SRC c 72 | //@{ 73 | int foo(int a) { 74 | return a+1; 75 | } 76 | //@} 77 | #+END_SRC 78 | 79 | This "comment continuation" should probably be configurable for each pair. 80 | 81 | Not all modes provide comments that are specified in syntax tables, for example org mode uses line-initial # for this. Should we provide a callback to check for such contexts? 82 | 83 | ** org comment block :research: 84 | Org mode has comment blocks: 85 | 86 | #+BEGIN_COMMENT 87 | #+END_COMMENT 88 | 89 | Should we treat these as comments? 90 | 91 | ** org src block :research: 92 | If we are outside of a src block, we should treat it as comment. If we are inside, we might at least change =major-mode= variable to the apropriate mode. Getting the correct syntax tables would also be cool, but is this safe? 93 | 94 | ** code 95 | Ignore strings, comments, org blocks. 96 | 97 | ** custom context 98 | A predicate that is called on each match, deciding if we are in "this context" or not. 99 | 100 | * Thing types 101 | The generally supported "parsers" or things are: 102 | - symbol 103 | - sexp (i.e. pair with different opening and closing) 104 | - string-like (i.e. pair with same opening and closing) 105 | - sgml tag (special parser for performance) 106 | -------------------------------------------------------------------------------- /dev/_old/presentation2.org: -------------------------------------------------------------------------------- 1 | * forward/backward 2 | ** prefix commands 3 | 4 | - tag object 5 | - pair object 6 | - symbol object 7 | ** numeric prefix 8 | - move that many times 9 | 10 | * next/previous 11 | - if at the end of the expression, move up forward/backward 12 | ** numeric prefix 13 | - move that many times 14 | 15 | * up/backward up 16 | - reindent the expression 17 | 18 | ** numeric prefix 19 | - move that many levels up 20 | 21 | * down/backward down 22 | ** prefix 23 | - numeric = move that many levels down 24 | - raw = move down as much as possible 25 | - double raw = move to the beginning of sexp 26 | (same as if there's nothing to go down to) 27 | 28 | * beginning of sexp/end of sexp. 29 | ** prefix 30 | - numeric = move to beginning of Nth expression 31 | - raw = move to beginning of parent expression 32 | 33 | * select next thing 34 | ** prefix 35 | - numeric = select that many things 36 | - raw = select up until the end of exp 37 | - double raw = select current expr 38 | -- selecting again selects the inside. 39 | 40 | * pouzity buffer 41 | 42 | ;; * forward/backward 43 | ;; ** numeric prefix 44 | ;; - move that many times 45 | 46 | (defun sp-forward-sexp (&optional arg) 47 | (interactive "p") 48 | (setq arg (or arg 1))) 49 | 50 | (defun sp-forward-sexp (&optional arg) (interactive "p") (setq arg (or arg 1))) 51 | 52 | ;; ** prefix commands 53 | ;; - tag object 54 | 55 | some words [

and a paragraph

and more words ] and whatever (maybe a little expression here) 56 | 57 | ;; - pair object 58 | 59 | some words [

and a paragraph

and more words ] and whatever (maybe a little expression here) 60 | 61 | ;; - symbol object 62 | 63 | some words [

and a paragraph

and more words ] and whatever (maybe a little expression here) 64 | 65 | ;; * next/previous 66 | ;; - if at the end of the expression, move up forward/backward 67 | ;; ** numeric prefix 68 | ;; - move that many times 69 | 70 | (defun sp-forward-sexp (&optional arg) (interactive "p") (setq arg (or arg 1))) 71 | 72 | (let ((enc (sp-get-enclosing-sexp))) 73 | (if enc 74 | (save-excursion 75 | (if (> arg 0) 76 | (progn 77 | (goto-char (sp-get enc :end-in))))) 78 | (error "No enclosing expression"))) 79 | 80 | ;; * up/backward up 81 | ;; - reindent the expression 82 | ;; ** numeric prefix 83 | ;; - move that many levels up 84 | 85 | (cond 86 | ((equal arg '(4)) 87 | (sp-splice-sexp-killing-backward 1)) 88 | ((equal arg '(-4)) 89 | (sp-splice-sexp-killing-forward 1)) 90 | (t 91 | (let ((ok (sp-get-enclosing-sexp)) str) 92 | (when ok 93 | (sp-select-next-thing-exchange arg))))) 94 | 95 | ;; * down/backward down 96 | ;; ** prefix 97 | ;; - numeric = move that many levels down 98 | ;; - raw = move down as much as possible 99 | ;; - double raw = move to the beginning of sexp 100 | ;; (same as if there's nothing to go down to) 101 | 102 | (cond 103 | ((equal arg '(4)) 104 | (sp-splice-sexp-killing-backward 1)) 105 | ((equal arg '(-4)) 106 | (sp-splice-sexp-killing-forward 1)) 107 | (t 108 | (let ((ok (sp-get-enclosing-sexp)) str) 109 | (when ok 110 | (sp-select-next-thing-exchange arg))))) 111 | 112 | (if (> arg 0) nil 'end) 113 | 114 | ;; * beginning of sexp/end of sexp. 115 | ;; ** prefix 116 | ;; - numeric = move to beginning of Nth expression 117 | ;; - raw = move to beginning of parent expression 118 | 119 | (let* ((old (point)) 120 | (raise (progn 121 | (sp-beginning-of-sexp) 122 | (buffer-substring (point) old)))) 123 | (dee-region (point) old) 124 | (sp-backward-slurp-sexp arg) 125 | (sp-forward-whitespace) 126 | (sp-beginning-of-sexp) 127 | (insert raise) 128 | (save-excursion 129 | (sp-backward-up-sexp) 130 | (indent-sexp))) 131 | 132 | ;; * select next thing 133 | ;; ** prefix 134 | ;; - numeric = select that many things 135 | ;; - raw = select up until the end of exp 136 | ;; - double raw = select current expr 137 | ;; -- selecting again selects the inside. 138 | 139 | (let* ((old (point)) 140 | (raise (progn 141 | (sp-beginning-of-sexp) 142 | (buffer-substring (point) old)))) 143 | (delete-region (point) old) 144 | (sp-backward-slurp-sexp arg) 145 | (sp-forward-whitespace) 146 | (sp-beginning-of-sexp) 147 | (insert raise) 148 | (save-excursion 149 | (sp-backward-up-sexp) 150 | (indent-sexp))) 151 | 152 | ;; --------------------------------------------- 153 | ;; --------------------------------------------- 154 | 155 | 156 | [ 157 | verba arcana 158 |

159 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent 160 | libero orci, [auctor sed, faucibus vestibulum, gravida vitae,] 161 | arcu. (Nunc posuere. Suspendisse potenti. Praesent) in arcu ac nisl 162 | ultricies ultricies. Fusce eros. Sed pulvinar vehicula 163 |

164 | 165 | ] 166 | 167 |

168 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Praesent 169 | libero orci, [auctor sed, faucibus vestibulum, gravida vitae,] 170 | arcu. (Nunc posuere. Suspendisse potenti. Praesent) in arcu ac nisl 171 | ultricies ultricies. Fusce eros. Sed pulvinar vehicula 172 |

173 | -------------------------------------------------------------------------------- /smartparens-python.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-python.el --- Additional configuration for Python based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2018, 2020, 2022-2023 Matus Goljer 4 | 5 | ;; Author: Matus Goljer 6 | ;; Maintainer: Matus Goljer 7 | ;; Created: 8 February 2015 8 | ;; Keywords: abbrev convenience editing 9 | ;; URL: https://github.com/Fuco1/smartparens 10 | 11 | ;; This file is not part of GNU Emacs. 12 | 13 | ;;; License: 14 | 15 | ;; This file is part of Smartparens. 16 | 17 | ;; Smartparens is free software; you can redistribute it and/or modify 18 | ;; it under the terms of the GNU General Public License as published by 19 | ;; the Free Software Foundation, either version 3 of the License, or 20 | ;; (at your option) any later version. 21 | 22 | ;; Smartparens is distributed in the hope that it will be useful, 23 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | ;; GNU General Public License for more details. 26 | 27 | ;; You should have received a copy of the GNU General Public License 28 | ;; along with Smartparens. If not, see . 29 | 30 | ;;; Commentary: 31 | 32 | ;; This file provides some additional configuration for Python based 33 | ;; modes. To use it, simply add: 34 | ;; 35 | ;; (require 'smartparens-python) 36 | ;; 37 | ;; into your configuration. You can use this in conjunction with the 38 | ;; default config or your own configuration. 39 | ;; 40 | ;; If you have good ideas about what should be added please file an 41 | ;; issue on the github tracker. 42 | ;; 43 | ;; For more info, see github readme at 44 | ;; https://github.com/Fuco1/smartparens 45 | 46 | ;;; Code: 47 | 48 | (require 'smartparens) 49 | 50 | (defgroup smartparens-python () 51 | "smartparens settings for python-mode" 52 | :group 'smartparens) 53 | 54 | (defcustom sp-python-insert-colon-in-function-definitions nil 55 | "If non-nil, auto-insert a colon after parens insertion in definition. 56 | 57 | Supported definitions are: 58 | 59 | - def 60 | - async def 61 | - class" 62 | :group 'smartparens-python 63 | :type 'boolean) 64 | 65 | ;; Python has no sexp suffices. This fixes slurping 66 | ;; (|sys).path.append---the dot should not travel with the closing 67 | ;; paren 68 | (--each '(python-mode python-ts-mode inferior-python-mode) 69 | (add-to-list 'sp-sexp-suffix (list it 'regexp ""))) 70 | 71 | (defun sp-python-maybe-add-colon-python (_id action _context) 72 | "Adds a colon after parentheses in a python definition. 73 | 74 | Works for (async) def forms and class forms. 75 | 76 | See also the option `sp-python-insert-colon-in-function-definitions'." 77 | ;; here, caret supposed to be in between parens, i.e. (|) 78 | (when (and sp-python-insert-colon-in-function-definitions 79 | (eq action 'insert) 80 | (looking-at ")\\s-*$") 81 | (save-excursion 82 | (goto-char (line-beginning-position)) 83 | (re-search-forward 84 | (rx bol 85 | (* (syntax whitespace)) 86 | (? "async") 87 | (* (syntax whitespace)) 88 | (or "def" "class") 89 | word-boundary) 90 | (line-end-position) 91 | t))) 92 | (save-excursion 93 | (forward-char) ;; skip closing paren 94 | (insert ":")))) 95 | 96 | (sp-with-modes '(python-mode python-ts-mode) 97 | (sp-local-pair "'" "'" :unless '(sp-in-comment-p sp-in-string-quotes-p) :post-handlers '(:add sp-python-fix-tripple-quotes)) 98 | (sp-local-pair "\"" "\"" :post-handlers '(:add sp-python-fix-tripple-quotes)) 99 | (sp-local-pair "'''" "'''") 100 | (sp-local-pair "\\'" "\\'") 101 | (sp-local-pair "\"\"\"" "\"\"\"") 102 | (sp-local-pair "(" ")" :post-handlers '(:add sp-python-maybe-add-colon-python))) 103 | 104 | (defun sp-python-fix-tripple-quotes (id action _context) 105 | "Properly rewrap tripple quote pairs. 106 | 107 | When the user rewraps a tripple quote pair to the other pair 108 | type (i.e. ''' to \") we check if the old pair was a 109 | tripple-quote pair and if so add two pairs to beg/end of the 110 | newly formed pair (which was a single-quote \"...\" pair)." 111 | (when (eq action 'rewrap-sexp) 112 | (let ((old (plist-get sp-handler-context :parent))) 113 | (when (or (and (equal old "'''") (equal id "\"")) 114 | (and (equal old "\"\"\"") (equal id "'"))) 115 | (save-excursion 116 | (sp-get sp-last-wrapped-region 117 | (goto-char :end-in) 118 | (insert (make-string 2 (aref id 0))) 119 | (goto-char :beg) 120 | (insert (make-string 2 (aref id 0))))))))) 121 | 122 | (defadvice python-indent-dedent-line-backspace 123 | (around sp-backward-delete-char-advice activate) 124 | "Fix indend." 125 | (if smartparens-strict-mode 126 | (cl-letf (((symbol-function 'delete-backward-char) 127 | (lambda (arg &optional killp) 128 | (sp-backward-delete-char arg)))) 129 | ad-do-it) 130 | ad-do-it)) 131 | 132 | (provide 'smartparens-python) 133 | ;;; smartparens-python.el ends here 134 | -------------------------------------------------------------------------------- /test/smartparens-show-mode-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens) 2 | (require 'evil) 3 | 4 | (defmacro sp-test--show-pairs (initial init-form &rest forms) 5 | (declare (indent 2)) 6 | `(let ((sp-pairs 7 | '((t . 8 | ((:open "\"" :close "\"" :actions (insert wrap autoskip navigate)) 9 | (:open "'" :close "'" :actions (insert wrap autoskip navigate)) 10 | (:open "$" :close "$" :actions (insert wrap autoskip navigate)) 11 | (:open "(" :close ")" :actions (insert wrap autoskip navigate)) 12 | (:open "[" :close "]" :actions (insert wrap autoskip navigate)) 13 | (:open "{" :close "}" :actions (insert wrap autoskip navigate)))))) 14 | (sp-show-pair-overlays nil)) 15 | (unwind-protect 16 | (sp-test-with-temp-buffer ,initial 17 | ,init-form 18 | (show-smartparens-mode 1) 19 | (smartparens-mode 1) 20 | (shut-up (sp-show--pair-function)) 21 | ,@forms) 22 | (sp-show--pair-delete-overlays)))) 23 | 24 | (defun sp-test--show-pairs-assert (result) 25 | (let ((op-beg (plist-get result :op-beg)) 26 | (op-len (or (plist-get result :op-len) 1)) 27 | (cl-beg (plist-get result :cl-beg)) 28 | (cl-len (or (plist-get result :cl-len) 1)) 29 | (op (nth 0 sp-show-pair-overlays)) 30 | (cl (nth 2 sp-show-pair-overlays))) 31 | (if (and (not op-beg) (not cl-beg)) 32 | (should (eq sp-show-pair-overlays nil)) 33 | (if (not op-beg) 34 | (should (null op)) 35 | (should (not (null op))) 36 | (should (= (overlay-start op) op-beg)) 37 | (should (= (overlay-end op) (+ op-beg op-len)))) 38 | (if (not cl-beg) 39 | (should (null cl)) 40 | (should (not (null cl))) 41 | (should (= (overlay-start cl) cl-beg)) 42 | (should (= (overlay-end cl) (+ cl-beg cl-len))))))) 43 | 44 | (ert-deftest sp-test-show-mode-point-at-nonpairable-stringlike-delimiter-textmode () 45 | (sp-test--show-pairs "\"asdasd'| asdasd asd\"" (text-mode) 46 | (sp-test--show-pairs-assert nil))) 47 | 48 | (sp-ert-deftest sp-test-show-mode-point-elisp 49 | :let ((sp-show-pair-from-inside nil)) 50 | (sp-test--show-pairs "|(foo bar)" (emacs-lisp-mode) 51 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 9))) 52 | (sp-test--show-pairs "(foo bar)|" (emacs-lisp-mode) 53 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 9))) 54 | 55 | (sp-test--show-pairs "(|foo bar)" (emacs-lisp-mode) 56 | (sp-test--show-pairs-assert nil)) 57 | (sp-test--show-pairs "(foo bar|)" (emacs-lisp-mode) 58 | (sp-test--show-pairs-assert nil)) 59 | 60 | (sp-test--show-pairs "\"()|\"" (emacs-lisp-mode) 61 | (sp-test--show-pairs-assert (list :op-beg 2 :cl-beg 3))) 62 | (sp-test--show-pairs "\"()\"|" (emacs-lisp-mode) 63 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 4)))) 64 | 65 | (sp-ert-deftest sp-test-show-mode-point-elisp-from-inside-t 66 | :let ((sp-show-pair-from-inside t)) 67 | (sp-test--show-pairs "(|foo bar)" (emacs-lisp-mode) 68 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 9))) 69 | (sp-test--show-pairs "(foo bar|)" (emacs-lisp-mode) 70 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 9)))) 71 | 72 | (sp-ert-deftest sp-test-show-mode-latex-multiple-nested-sexps 73 | (sp-test--show-pairs "|$({})$" (latex-mode) 74 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 6))) 75 | (sp-test--show-pairs "$|({})$" (latex-mode) 76 | (sp-test--show-pairs-assert (list :op-beg 2 :cl-beg 5))) 77 | (sp-test--show-pairs "$(|{})$" (latex-mode) 78 | (sp-test--show-pairs-assert (list :op-beg 3 :cl-beg 4))) 79 | (sp-test--show-pairs "$({|})$" (latex-mode) 80 | (sp-test--show-pairs-assert nil)) 81 | (sp-test--show-pairs "$({}|)$" (latex-mode) 82 | (sp-test--show-pairs-assert (list :op-beg 3 :cl-beg 4))) 83 | (sp-test--show-pairs "$({})|$" (latex-mode) 84 | (sp-test--show-pairs-assert (list :op-beg 2 :cl-beg 5))) 85 | (sp-test--show-pairs "$({})$|" (latex-mode) 86 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 6)))) 87 | 88 | (sp-ert-deftest sp-test-show-mode-latex-multiple-nested-sexps-from-inside-t 89 | :let ((sp-show-pair-from-inside t)) 90 | (sp-test--show-pairs "|$({})$" (latex-mode) 91 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 6))) 92 | (sp-test--show-pairs "$|({})$" (latex-mode) 93 | (sp-test--show-pairs-assert (list :op-beg 2 :cl-beg 5))) 94 | (sp-test--show-pairs "$(|{})$" (latex-mode) 95 | (sp-test--show-pairs-assert (list :op-beg 3 :cl-beg 4))) 96 | (sp-test--show-pairs "$({|})$" (latex-mode) 97 | (sp-test--show-pairs-assert (list :op-beg 3 :cl-beg 4))) 98 | (sp-test--show-pairs "$({}|)$" (latex-mode) 99 | (sp-test--show-pairs-assert (list :op-beg 3 :cl-beg 4))) 100 | (sp-test--show-pairs "$({})|$" (latex-mode) 101 | (sp-test--show-pairs-assert (list :op-beg 2 :cl-beg 5))) 102 | (sp-test--show-pairs "$({})$|" (latex-mode) 103 | (sp-test--show-pairs-assert (list :op-beg 1 :cl-beg 6)))) 104 | 105 | (ert-deftest sp-test-show-mode-point-at-end-in-sexp-evil () 106 | (let ((sp-pairs '((t . ((:open "(" :close ")" :actions (insert wrap autoskip navigate)))))) 107 | (sp-show-pair-overlays nil)) 108 | (unwind-protect 109 | (sp-test-with-temp-elisp-buffer "(foo bar|)" 110 | (evil-local-mode) 111 | (show-smartparens-mode 1) 112 | (sp-show--pair-function) 113 | (should (not (eq sp-show-pair-overlays nil)))) 114 | (sp-show--pair-delete-overlays)))) 115 | -------------------------------------------------------------------------------- /test/smartparens-python-test.el: -------------------------------------------------------------------------------- 1 | (require 'smartparens-python) 2 | 3 | (defun sp-test--python-mode () 4 | (shut-up (python-mode))) 5 | 6 | (defun sp-test-insertion-python (initial keys result) 7 | (sp-test-with-temp-buffer initial 8 | (sp-test--python-mode) 9 | (execute-kbd-macro keys) 10 | (sp-buffer-equals result))) 11 | 12 | (ert-deftest sp-test-dont-reindent-python () 13 | (sp-test-with-temp-buffer "if foo: 14 | bar() 15 | baz = biz.boz|" 16 | (sp-test--python-mode) 17 | (sp-backward-kill-word 1) 18 | (should (equal (buffer-string) "if foo: 19 | bar() 20 | baz = biz.")))) 21 | 22 | (ert-deftest sp-test-python-slurp-whitespace () 23 | "Ensure we don't add unwanted whitespace when slurping." 24 | (sp-test-with-temp-buffer "foo(|bar)(baz)" 25 | (sp-test--python-mode) 26 | (sp-forward-slurp-sexp) 27 | (should (equal (buffer-string) "foo(bar(baz))")))) 28 | 29 | (ert-deftest sp-test-python-square-bracket-whitespace () 30 | "Ensure we don't add unwanted whitespace when slurping." 31 | (sp-test-with-temp-buffer "foo[|bar][baz]" 32 | (sp-test--python-mode) 33 | (sp-forward-slurp-sexp) 34 | (should (equal (buffer-string) "foo[bar[baz]]")))) 35 | 36 | (ert-deftest sp-test-python-backspace-in-strict-mode () 37 | (sp-test-with-temp-buffer "def foo()|:" 38 | (progn (sp-test--python-mode) 39 | (smartparens-strict-mode +1)) 40 | (execute-kbd-macro (kbd "DEL")) 41 | (should (equal (buffer-string) "def foo():")))) 42 | 43 | (ert-deftest sp-test-python-apostrophe-in-string () 44 | "When inserting ' in a string, don't insert a matched '." 45 | (sp-test-with-temp-buffer "\" | \"" 46 | (sp-test--python-mode) 47 | (execute-kbd-macro "'") 48 | (should (equal (buffer-string) "\" ' \"")))) 49 | 50 | (ert-deftest sp-test-python-apostrophe-in-comment () 51 | "When inserting ' in a comment, don't insert a matched '." 52 | (sp-test-with-temp-buffer "# |" 53 | (sp-test--python-mode) 54 | (execute-kbd-macro "'") 55 | (should (equal (buffer-string) "# '")))) 56 | 57 | (ert-deftest sp-test-python-apostrophe-in-code () 58 | "When inserting ' in code, insert a matching '." 59 | (sp-test-with-temp-buffer "" 60 | (sp-test--python-mode) 61 | (execute-kbd-macro "'") 62 | (should (equal (buffer-string) "''")))) 63 | 64 | (ert-deftest sp-test-python-apostrophe-skip-closing-in-code () 65 | "When inserting ' at the end of '-delimited string, skip it." 66 | (sp-test-with-temp-buffer "" 67 | (sp-test--python-mode) 68 | (execute-kbd-macro "'foo'") 69 | (should (equal (buffer-string) "'foo'")) 70 | (should (eobp)))) 71 | 72 | (ert-deftest sp-test-python-apostrophe-skip-closing-after-edit-in-code () 73 | "When inserting ' at the end of '-delimited string, skip it. 74 | 75 | Make sure to skip even in inactive sexps." 76 | (sp-test-with-temp-buffer "" 77 | (sp-test--python-mode) 78 | (execute-kbd-macro "'foo\C-b\C-db'") 79 | (should (equal (buffer-string) "'fob'")) 80 | (should (eobp)))) 81 | 82 | (ert-deftest sp-test-python-apostrophe-delete-on-backspace-in-comment () 83 | "When backspacing over ' it should be deleted." 84 | (sp-test-with-temp-buffer "\"foo; it's| a nice word!\"" 85 | (sp-test--python-mode) 86 | (execute-kbd-macro (kbd "|")) 87 | (should (equal (buffer-string) "\"foo; | a nice word!\"")))) 88 | 89 | (ert-deftest sp-test-python-apostrophe-is-escaped-in-apostrophe-string () 90 | "When inside a '' delimited string, escape inserted '." 91 | (sp-test-with-temp-buffer "a = 'foo | bar'" 92 | (sp-test--python-mode) 93 | (execute-kbd-macro (kbd "'")) 94 | (insert "|") 95 | (should (equal (buffer-string) "a = 'foo \\'| bar'")))) 96 | 97 | (ert-deftest sp-test-python-apostrophe-is-not-escaped-in-doublequote-string () 98 | "When inside a '' delimited string, escape inserted '." 99 | (sp-test-with-temp-buffer "a = \"foo | bar\"" 100 | (sp-test--python-mode) 101 | (execute-kbd-macro (kbd "'")) 102 | (insert "|") 103 | (should (equal (buffer-string) "a = \"foo '| bar\"")))) 104 | 105 | (ert-deftest sp-test-python-quote-do-not-escape-if-string-unbalanced () 106 | "See `sp-test-insert-quote-do-not-escape-if-string-unbalanced'." 107 | (sp-test-insertion-python "[\"asd|]" "\"" "[\"asd\"|]") 108 | (sp-test-insertion-python "\"foo |] bar\"" "\"" "\"foo \\\"|] bar\"") 109 | (sp-test-insertion-python "\"first| \"second\"" "\"" "\"first\"| \"second\"")) 110 | 111 | (ert-deftest sp-test-python-rewrap-tripple-single-quote-to-double-quote () 112 | "Test if '''...''' is rewrapped to \"\"\"...\"\"\" when the user selects \" as rewrapping pair." 113 | (sp-test-with-temp-buffer "'''f|oo'''" 114 | (sp-test--python-mode) 115 | (sp-rewrap-sexp '("\"" . "\"")) 116 | (sp-buffer-equals "\"\"\"f|oo\"\"\""))) 117 | 118 | (ert-deftest sp-test-python-rewrap-tripple-double-quote-to-single-quote () 119 | "Test if \"\"\"...\"\"\" is rewrapped to '''...''' when the user selects ' as rewrapping pair." 120 | (sp-test-with-temp-buffer "\"\"\"f|oo\"\"\"" 121 | (sp-test--python-mode) 122 | (sp-rewrap-sexp '("'" . "'")) 123 | (sp-buffer-equals "'''f|oo'''"))) 124 | 125 | (ert-deftest sp-test-python-autoinsert-colon-on-def () 126 | (sp-test-with-temp-buffer "def foo|" 127 | (sp-test--python-mode) 128 | (execute-kbd-macro (kbd "(")) 129 | (sp-buffer-equals "def foo(|):"))) 130 | 131 | (ert-deftest sp-test-python-autoinsert-colon-on-class () 132 | (sp-test-with-temp-buffer "class Foo|" 133 | (sp-test--python-mode) 134 | (execute-kbd-macro (kbd "(")) 135 | (sp-buffer-equals "class Foo(|):"))) 136 | -------------------------------------------------------------------------------- /smartparens-rust.el: -------------------------------------------------------------------------------- 1 | ;;; smartparens-rust.el --- Additional configuration for Rust based modes. -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2019 Wilfred Hughes 4 | 5 | ;; Created: 3 November 2015 6 | ;; Keywords: abbrev convenience editing 7 | ;; URL: https://github.com/Fuco1/smartparens 8 | 9 | ;; This file is not part of GNU Emacs. 10 | 11 | ;;; License: 12 | 13 | ;; This file is part of Smartparens. 14 | 15 | ;; Smartparens is free software; you can redistribute it and/or modify 16 | ;; it under the terms of the GNU General Public License as published by 17 | ;; the Free Software Foundation, either version 3 of the License, or 18 | ;; (at your option) any later version. 19 | 20 | ;; Smartparens is distributed in the hope that it will be useful, 21 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | ;; GNU General Public License for more details. 24 | 25 | ;; You should have received a copy of the GNU General Public License 26 | ;; along with Smartparens. If not, see . 27 | 28 | ;;; Commentary: 29 | 30 | ;; This file provides some additional configuration for Rust. To use 31 | ;; it, simply add: 32 | ;; 33 | ;; (require 'smartparens-config) 34 | ;; 35 | ;; alternatively, you can explicitly load these preferences: 36 | ;; 37 | ;; (require 'smartparens-rust) 38 | ;; 39 | ;; in your configuration. 40 | 41 | ;; For more info, see github readme at 42 | ;; https://github.com/Fuco1/smartparens 43 | 44 | ;;; Code: 45 | (require 'smartparens) 46 | 47 | (declare-function rust-mode "rust-mode") 48 | (declare-function rust-ts-mode "rust-ts-mode") 49 | (declare-function rustic-mode "rustic-mode") 50 | 51 | (defun sp-in-rust-lifetime-context (&rest _args) 52 | "Return t if point is in a Rust context where ' represents a lifetime. 53 | If we return nil, ' should be used for character literals. 54 | ARGS." 55 | (or 56 | (condition-case nil 57 | ;; If point is just after a &', it's probably a &'foo. 58 | (save-excursion 59 | (backward-char 2) 60 | (looking-at "&")) 61 | ;; If we're at the beginning of the buffer, just carry on. 62 | (beginning-of-buffer)) 63 | ;; If point is inside < > it's probably a parameterised function. 64 | (let ((paren-pos (nth 1 (syntax-ppss)))) 65 | (and paren-pos 66 | (save-excursion 67 | (goto-char paren-pos) 68 | (looking-at "<")))))) 69 | 70 | (defun sp-rust-skip-match-angle-bracket (_ms _mb me) 71 | "Non-nil if we should ignore the bracket as valid delimiter." 72 | (save-excursion 73 | (goto-char me) 74 | (let ((on-fn-return-type 75 | (sp--looking-back-p (rx "->") nil)) 76 | (on-match-branch 77 | (sp--looking-back-p (rx "=>") nil)) 78 | (on-comparison 79 | (sp--looking-back-p (rx (or 80 | (seq space "<") 81 | (seq space ">") 82 | (seq space "<<") 83 | (seq space ">>"))) 84 | nil))) 85 | (or on-comparison on-fn-return-type on-match-branch)))) 86 | 87 | (defun sp-rust-filter-angle-brackets (_id action context) 88 | "Non-nil if we should allow ID's ACTION in CONTEXT for angle brackets." 89 | ;; See the docstring for `sp-pair' for the possible values of ID, 90 | ;; ACTION and CONTEXT. 91 | (cond 92 | ;; Inside strings, don't do anything with < or >. 93 | ((eq context 'string) 94 | nil) 95 | ;; Don't do any smart pairing inside comments either. 96 | ((eq context 'comment) 97 | nil) 98 | ;; Otherwise, we're in code. 99 | ((eq context 'code) 100 | (let ((on-fn-return-type 101 | (looking-back (rx "->") nil)) 102 | (on-match-branch 103 | (looking-back (rx "=>") nil)) 104 | (on-comparison 105 | (looking-back (rx (or 106 | (seq space "<") 107 | (seq space ">") 108 | (seq space "<<") 109 | (seq space ">>"))) 110 | nil))) 111 | (cond 112 | ;; Only insert a matching > if we're not looking at a 113 | ;; comparison. 114 | ((eq action 'insert) 115 | (and (not on-comparison) (not on-fn-return-type) (not on-match-branch))) 116 | ;; Always allow wrapping in a pair if the region is active. 117 | ((eq action 'wrap) 118 | (not on-match-branch)) 119 | ;; When pressing >, autoskip if we're not looking at a 120 | ;; comparison. 121 | ((eq action 'autoskip) 122 | (and (not on-comparison) (not on-fn-return-type) (not on-match-branch))) 123 | ;; Allow navigation, highlighting and strictness checks if it's 124 | ;; not a comparison. 125 | ((eq action 'navigate) 126 | (and (not on-comparison) (not on-fn-return-type) (not on-match-branch)))))))) 127 | 128 | (sp-with-modes '(rust-mode rust-ts-mode rustic-mode) 129 | (sp-local-pair "'" "'" 130 | :unless '(sp-in-comment-p sp-in-string-quotes-p sp-in-rust-lifetime-context) 131 | :post-handlers'(:rem sp-escape-quotes-after-insert)) 132 | (sp-local-pair "<" ">" 133 | :when '(sp-rust-filter-angle-brackets) 134 | :skip-match 'sp-rust-skip-match-angle-bracket)) 135 | 136 | ;; Rust has no sexp suffices. This fixes slurping 137 | ;; (|foo).bar -> (foo.bar) 138 | (add-to-list 'sp-sexp-suffix (list #'rust-mode 'regexp "")) 139 | (add-to-list 'sp-sexp-suffix (list #'rust-ts-mode 'regexp "")) 140 | (add-to-list 'sp-sexp-suffix (list #'rustic-mode 'regexp "")) 141 | 142 | (provide 'smartparens-rust) 143 | 144 | ;;; smartparens-rust.el ends here 145 | -------------------------------------------------------------------------------- /test/smartparens-rust-test.el: -------------------------------------------------------------------------------- 1 | (require 'rust-mode) 2 | (require 'smartparens) 3 | 4 | (ert-deftest sp-test-rust-parameterized-lifetimes () 5 | "When inserting ' in a <>, don't treat it as a character." 6 | (sp-test-with-temp-buffer "fn foo<|>(x: T) {}" 7 | (rust-mode) 8 | (execute-kbd-macro "'a") 9 | (should (equal (buffer-string) "fn foo<'a>(x: T) {}")))) 10 | 11 | (ert-deftest sp-test-rust-ampersand-parameter () 12 | "When inserting ' in a &'foo, don't treat it as a character." 13 | (sp-test-with-temp-buffer "fn foo(x: |T) {}" 14 | (rust-mode) 15 | (execute-kbd-macro "&'a ") 16 | (should (equal (buffer-string) "fn foo(x: &'a T) {}")))) 17 | 18 | (ert-deftest sp-test-rust-character-literal () 19 | "When inserting ' for a character literal, insert the closing '." 20 | (sp-test-with-temp-buffer "let x = |" 21 | (rust-mode) 22 | (execute-kbd-macro "'a") 23 | (should (equal (buffer-string) "let x = 'a'")))) 24 | 25 | (ert-deftest sp-test-rust-character-in-comment () 26 | "When inserting ' in a comment, don't bother matching it." 27 | (sp-test-with-temp-buffer "// |" 28 | (rust-mode) 29 | (execute-kbd-macro "'") 30 | (should (equal (buffer-string) "// '")))) 31 | 32 | (ert-deftest sp-test-rust-character-in-string () 33 | "When inserting ' in a string, don't insert a matched '." 34 | (sp-test-with-temp-buffer "let x = \"|\";" 35 | (rust-mode) 36 | (execute-kbd-macro "'") 37 | (should (equal (buffer-string) "let x = \"'\";")))) 38 | 39 | (ert-deftest sp-test-rust-kill-first-line () 40 | "Ensure we can kill words on the first line. 41 | Regression test." 42 | (sp-test-with-temp-buffer "extern|" 43 | (rust-mode) 44 | (sp-backward-kill-word 1) 45 | (should (equal (buffer-string) "")))) 46 | 47 | (ert-deftest sp-test-rust-pair-angle-bracket () 48 | "When typing < we should insert the matching pair 49 | \(when appropriate\)." 50 | (sp-test-with-temp-buffer "Option|" 51 | (rust-mode) 52 | (execute-kbd-macro "<") 53 | ;; We should have inserted a pair. 54 | (should (equal (buffer-string) "Option<>")))) 55 | 56 | (ert-deftest sp-test-rust-forward-angle-bracket () 57 | "< and > are usually brackets in Rust." 58 | (sp-test-with-temp-buffer "struct Foo { 59 | baz: Baz| 60 | }" 61 | (rust-mode) 62 | (sp-forward-sexp) 63 | ;; We should have moved over the closing >. 64 | (should (looking-at "\n")))) 65 | 66 | (ert-deftest sp-test-rust-less-than () 67 | "When using < to compare, don't insert >." 68 | (sp-test-with-temp-buffer "if x |" 69 | (rust-mode) 70 | (execute-kbd-macro "<") 71 | (should (equal (buffer-string) "if x <")))) 72 | 73 | (ert-deftest sp-test-rust-left-shift () 74 | "When using << for a left shift, don't insert >." 75 | (sp-test-with-temp-buffer "if x <|" 76 | (rust-mode) 77 | (execute-kbd-macro "<") 78 | (should (equal (buffer-string) "if x <<")))) 79 | 80 | (ert-deftest sp-test-rust-left-shift-then-function () 81 | "We should still be able to insert -> after a left shift." 82 | (sp-test-with-temp-buffer "const y: u64 = 1 << 2; 83 | 84 | fn foo(x: u64) -| 85 | 86 | fn bar(x: u64) -> bool { 87 | true 88 | } 89 | " 90 | (rust-mode) 91 | (smartparens-strict-mode) 92 | (execute-kbd-macro ">") 93 | (should (equal (buffer-substring (line-beginning-position) (line-end-position)) 94 | "fn foo(x: u64) ->")))) 95 | 96 | (ert-deftest sp-test-rust-delete-comparison () 97 | "We should be able to delete comparisons, even in strict mode." 98 | (sp-test-with-temp-buffer "a < b; b >|" 99 | (rust-mode) 100 | (smartparens-strict-mode) 101 | (execute-kbd-macro (kbd "")) 102 | (should (equal (buffer-string) "a < b; b ")))) 103 | 104 | (ert-deftest sp-test-rust-format-string () 105 | "Don't pair < when used in a format string." 106 | (sp-test-with-temp-buffer "println!(\"{:0|}\", x);" 107 | (rust-mode) 108 | (execute-kbd-macro "<") 109 | (should (equal (buffer-string) "println!(\"{:0<}\", x);")))) 110 | 111 | (ert-deftest sp-test-rust-pair-angle-bracket-in-function-call () 112 | "Pair < when parameterizing function calls." 113 | (sp-test-with-temp-buffer "iterator.collect::|" 114 | (rust-mode) 115 | (execute-kbd-macro "<") 116 | ;; We should have inserted a pair. 117 | (should (equal (buffer-string) "iterator.collect::<>")))) 118 | 119 | (ert-deftest sp-test-rust-pair-autoskip-closing-bracket () 120 | "Autoskip a matching >." 121 | (sp-test-with-temp-buffer "E" 122 | (rust-mode) 123 | (execute-kbd-macro ">") 124 | ;; We should have skipped the closing bracket. 125 | (should (equal (buffer-string) "E")))) 126 | 127 | (ert-deftest sp-test-rust-pair-insert-and-autoskip-closing-bracket () 128 | "Inserting multiples brackets and closing them." 129 | (sp-test-with-temp-buffer "E|" 130 | (rust-mode) 131 | (execute-kbd-macro ">>") 132 | ;; We should have inserted a pair without an extra chevron. 133 | (should (equal (buffer-string) "E>>")))) 134 | 135 | (ert-deftest sp-test-rust-insert-match-branch () 136 | "Inserting a match branch with a rocket (=>) operator." 137 | (sp-test-with-temp-buffer "match Some(1) { Some(n) =| }" 138 | (rust-mode) 139 | (execute-kbd-macro "> n") 140 | (should (equal (buffer-string) "match Some(1) { Some(n) => n }")))) 141 | 142 | ;; #793 143 | (ert-deftest sp-test-rust-skip-forward-over-return-type () 144 | "Moving forward over a function's return type." 145 | (sp-test-with-temp-buffer "fn foo() |-> u32" 146 | (rust-mode) 147 | (sp-forward-sexp) 148 | (execute-kbd-macro "{") 149 | (sp-buffer-equals "fn foo() -> u32{|}"))) 150 | 151 | ;; #793 152 | (ert-deftest sp-test-rust-skip-backward-over-return-type () 153 | "Moving backward over a function's return type." 154 | (sp-test-with-temp-buffer "foo() -> |u32 {}" 155 | (rust-mode) 156 | (smartparens-strict-mode 1) 157 | (sp-backward-sexp) 158 | (sp-buffer-equals "foo|() -> u32 {}"))) 159 | 160 | ;; #793 161 | (ert-deftest sp-test-rust-kill-defun () 162 | "Deleting a region containing a rust function definition." 163 | (sp-test-with-temp-buffer "|fn foo() ->u32 {}" 164 | (rust-mode) 165 | (mark-whole-buffer) 166 | (call-interactively 'sp-kill-region) 167 | (should (equal (buffer-string) "")))) 168 | -------------------------------------------------------------------------------- /dev/sp-defpair.org: -------------------------------------------------------------------------------- 1 | * Questions 2 | - how to edit previously specified rule? 3 | - how to add rule 4 | - in submode 5 | - how to remove rule 6 | - in submode 7 | - how to have a "matrix" of conditions 8 | 9 | #+BEGIN_SRC elisp 10 | (defmacro sp-defpair (&rest body) 11 | (declare (indent defun))) 12 | #+END_SRC 13 | 14 | * Inheritance 15 | Pairs can be defined in three scopes: globally, mode-locally and buffer-locally. All properties are automatically inherited down the chain: global < mode < buffer-local. 16 | 17 | Properties which are defined mode-locally /completely/ override global properties and properties which are defined buffer-locally /completely/ override global and mode-local properites. 18 | 19 | The old model of =:add= and =:rem= for list properties was removed due to unsound semantics. We also found that it was rarely used and the extra complexity was not warranted. 20 | 21 | If you call =sp-defpair= multiple times for the same pair on the same "level" (global, mode-local or buffer-local), the non-list properties are replaced and the list properties are concatenated. You can use a special value =:nil= to completely remove the property from the pair. 22 | 23 | *Note*: I'm not sure if we really want to remove this feature, probably just needs reworking. With the named configurations or anonymous settings it might be nice to be able to merge more stuff into the existing settings. 24 | 25 | We should probably opt for something like =docker-compose= or =hiera= or =neon= merging strategies. Those are well-defined and flexible. 26 | 27 | See this [[https://github.com/Fuco1/smartparens/issues/713#issuecomment-312457573][issue]] for the motivation: we want to be able to change behaviour selectively but not wipe all the config out. 28 | 29 | * data structure 30 | #+BEGIN_SRC elisp 31 | '(:open "do" 32 | :close "end" 33 | :trigger-wrap :undefined 34 | :trigger-insert :undefined 35 | :actions ((:type insert 36 | :active :undefined ;; can be set to nil to disable in inherited setting 37 | :when :undefined 38 | :unless (sp-ruby-in-string-or-word-p sp-in-comment-p) 39 | :after ("SPC" "RET" "")) 40 | (:type navigate 41 | :active :undefined 42 | :when :undefined 43 | :unless :undefined 44 | :after :undefined)) 45 | :pre-hook ((:function sp-ruby-pre-handler 46 | :on (slurp-backward barf-backward slurp-forward barf-forward) 47 | ;; if there is an after clause, the function is only 48 | ;; added to the "delayed" list on the specified 49 | ;; actions... if :on is unspecified, all actions are 50 | ;; taken automatically 51 | :when :undefined 52 | :unless :undefined 53 | :after :undefined)) 54 | :post-hook ((:function sp-ruby-block-post-handler 55 | :on (insert)) 56 | (:function sp-ruby-post-handler 57 | :on (barf-backward barf-forward))) 58 | :skip-match sp-ruby-skip-method-p 59 | :suffix "" 60 | :prefix :undefined 61 | :wrap :undefined 62 | :insert :undefined) 63 | #+END_SRC 64 | 65 | * API 66 | API copies the data structure as close as possible with the addition of these fields: 67 | - =:when= for a global "when" condition (this is stored under the when conditions of all the actions) 68 | - =:unless=, see =:when= 69 | - =:settings= which is an alist of a setting name (customizable) and a value; this can be used to override any smartparens global setting on a pair-by-pair basis 70 | 71 | * Example uses 72 | #+BEGIN_SRC elisp 73 | (sp-defpair 74 | :mode ruby-mode :open "do" :close "end" 75 | :actions (insert 76 | :unless sp-ruby-in-string-or-word-p sp-in-comment-p 77 | :after "SPC" "RET" "") 78 | navigate 79 | :pre-hook (sp-ruby-pre-handler :on slurp-backward barf-backward slurp-forward barf-forward) 80 | :post-hook 81 | (sp-ruby-block-post-handler :on insert) 82 | (sp-ruby-post-handler :on barf-backward barf-forward) 83 | :skip-match sp-ruby-skip-method-p 84 | :suffix "") 85 | #+END_SRC 86 | 87 | #+BEGIN_SRC elisp 88 | (sp-defpair 89 | :mode markdown-mode :open "*" 90 | ;; no :actions means all by default 91 | (insert :unless sp-point-at-bol-p) 92 | (navigate :unless sp--gfm-point-after-word-p) 93 | :post-hook ("[d1]" :after "SPC")) 94 | #+END_SRC 95 | 96 | #+BEGIN_SRC elisp 97 | (sp-defpair :mode c++-mode :open "/*" :close "*/" 98 | :post-hook (" | " :after "SPC") ("* ||\n[i]" :after "RET")) 99 | #+END_SRC 100 | 101 | #+BEGIN_SRC elisp 102 | (sp-defpair :mode php-mode :open "/**" :close "*/" 103 | :post-hook ("| " :after "SPC") (my-php-handle-docstring :after "RET")) 104 | #+END_SRC 105 | 106 | * Global x local x buffer-local 107 | #+BEGIN_SRC elisp 108 | ;; add pair globally 109 | (sp-defpair :open "-" :close "-") 110 | ;; add pair to emacs-lisp-mode buffers 111 | (sp-defpair :mode emacs-lisp-mode :open "-" :close "-") 112 | ;; add pair to local buffer only 113 | (sp-defpair :mode t :open "-" :close "-") 114 | #+END_SRC 115 | 116 | * Matrix conditions 117 | 118 | With the following configuraion =foo-hook= is only invoked on insert 119 | action in comment or wrap action in string. 120 | 121 | #+BEGIN_SRC elisp 122 | (sp-defpair 123 | :open "[" :close "]" 124 | :post-hook 125 | (foo-hook :on insert :when sp-in-comment) 126 | (foo-hook :on wrap :when sp-in-string)) 127 | #+END_SRC 128 | 129 | On the other hand, a /matrix/ condition specifies an each-to-each 130 | combination, so the in the following example =foo-hook= is invoked on 131 | either =insert= or =wrap= action whenever point is in comment or string (4 132 | combinations in total). 133 | 134 | #+BEGIN_SRC elisp 135 | (sp-defpair 136 | :open "[" :close "]" 137 | :post-hook 138 | (foo-hook :on insert wrap :when sp-in-comment sp-in-string)) 139 | #+END_SRC 140 | 141 | * Nezaradene 142 | #+BEGIN_SRC elisp 143 | (sp-defpair 144 | :open "'" 145 | :close "'" 146 | :when (sp-mode-is 'emacs-lisp-mode) 147 | :actions 148 | (insert :when sp-in-string-p) 149 | (wrap :when sp-in-string-p :unless (sp-string-quote-is "'")) 150 | (navigate :unless sp-eol-p) 151 | :post-handlers 152 | (sp-escape-wrapped-region :on wrap :when sp-in-comment-p)) 153 | 154 | (sp-local-pair 155 | 'emacs-lisp-mode 156 | :open "'" 157 | :actions 158 | (insert :unless sp-is-docstring-link-p) 159 | (:rem wrap) 160 | autoskip 161 | :post-handlers 162 | (sp-fix-slurp-space :on slurp-forward) 163 | :when 164 | (sp-mode-is 'emacs-lisp-mode)) 165 | #+END_SRC 166 | --------------------------------------------------------------------------------