Skip to content

Commit

Permalink
Support < and > in Rust with strict mode.
Browse files Browse the repository at this point in the history
Ensure that we can insert > in function signatures, or delete it in
comparisons and left shifts.
  • Loading branch information
Wilfred committed Jan 1, 2017
1 parent a677859 commit f661b7f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 20 deletions.
62 changes: 42 additions & 20 deletions smartparens-rust.el
Expand Up @@ -63,29 +63,51 @@ If we return nil, ' should be used for character literals."
(looking-at "<"))))))

(defun sp-rust-filter-angle-brackets (id action context)
"Return t if we should allow the ACTION in the current CONTEXT
for angle brackets."
"Return t if we should allow ACTION in the current CONTEXT
for angle brackets."
;; See the docstring for `sp-pair' for the possible values of ID,
;; ACTION and CONTEXT.
(cond
;; Disallow in format string after any character, since < is used to specify
;; alignment
((and (eq context 'string)
(looking-back (rx (seq alphanumeric "<")))) nil)

;; Disallow when inserting in code in two situations: 1) when '<' is used for
;; the comparison operators '<' and '<=', and 2) when writing a left shift
;; '<<'. In both cases, we assume the user will use a space before the
;; opening bracket '<'.
((and (eq context 'code)
(eq action 'insert)
(looking-back (rx (or (seq space "<")
(seq space "<<"))))) nil)

;; Otherwise, allow all actions
(t)))
;; Inside strings, don't do anything with < or >.
((eq context 'string)
nil)
;; Don't do any smart pairing inside comments either.
((eq context 'comment)
nil)
;; Otherwise, we're in code.
((eq context 'code)
(let ((on-fn-return-type
(looking-back (rx "->") nil))
(on-comparison
(looking-back (rx (or
(seq space "<")
(seq space ">")
(seq space "<<")
(seq space ">>")))
nil)))
(cond
;; Only insert a matching > if we're not looking at a
;; comparison.
((eq action 'insert)
(and (not on-comparison) (not on-fn-return-type)))
;; Always allow wrapping in a pair if the region is active.
((eq action 'wrap)
t)
;; When pressing >, autoskip if we're not looking at a
;; comparison.
((eq action 'autoskip)
(and (not on-comparison) (not on-fn-return-type)))
;; Allow navigation, highlighting and strictness checks if it's
;; not a comparison.
((eq action 'navigate)
(and (not on-comparison) (not on-fn-return-type))))))))

(sp-with-modes '(rust-mode)
(sp-local-pair "'" "'" :unless '(sp-in-comment-p sp-in-string-quotes-p sp-in-rust-lifetime-context) :post-handlers'(:rem sp-escape-quotes-after-insert))
(sp-local-pair "<" ">" :when '(sp-rust-filter-angle-brackets)))
(sp-local-pair "'" "'"
:unless '(sp-in-comment-p sp-in-string-quotes-p sp-in-rust-lifetime-context)
:post-handlers'(:rem sp-escape-quotes-after-insert))
(sp-local-pair "<" ">"
:when '(sp-rust-filter-angle-brackets)))

;; Rust has no sexp suffices. This fixes slurping
;; (|foo).bar -> (foo.bar)
Expand Down
24 changes: 24 additions & 0 deletions test/smartparens-rust-test.el
Expand Up @@ -77,6 +77,30 @@ Regression test."
(execute-kbd-macro "<")
(should (equal (buffer-string) "if x <<"))))

(ert-deftest sp-test-rust-left-shift-then-function ()
"We should still be able to insert -> after a left shift."
(sp-test-with-temp-buffer "const y: u64 = 1 << 2;
fn foo(x: u64) -|
fn bar(x: u64) -> bool {
true
}
"
(rust-mode)
(smartparens-strict-mode)
(execute-kbd-macro ">")
(should (equal (buffer-substring (line-beginning-position) (line-end-position))
"fn foo(x: u64) ->"))))

(ert-deftest sp-test-rust-delete-comparison ()
"We should be able to delete comparisons, even in strict mode."
(sp-test-with-temp-buffer "a < b; b >|"
(rust-mode)
(smartparens-strict-mode)
(execute-kbd-macro (kbd "<backspace>"))
(should (equal (buffer-string) "a < b; b "))))

(ert-deftest sp-test-rust-format-string ()
"Don't pair < when used in a format string."
(sp-test-with-temp-buffer "println!(\"{:0|}\", x);"
Expand Down

0 comments on commit f661b7f

Please sign in to comment.