[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/julia-mode dc21978 289/352: Merge pull request #63 from nv
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/julia-mode dc21978 289/352: Merge pull request #63 from nverno/movement-functions |
Date: |
Sun, 29 Aug 2021 11:23:04 -0400 (EDT) |
branch: elpa/julia-mode
commit dc219787b7576d90341470e69b2f3dbf2ef1836a
Merge: 6a0f756 10b0eff
Author: Yichao Yu <yyc1992@gmail.com>
Commit: GitHub <noreply@github.com>
Merge pull request #63 from nverno/movement-functions
beginning/end of defun functions
---
julia-mode-tests.el | 219 ++++++++++++++++++++++++++++++++++++++++++++--------
julia-mode.el | 135 ++++++++++++++++++++++++++++++--
2 files changed, 315 insertions(+), 39 deletions(-)
diff --git a/julia-mode-tests.el b/julia-mode-tests.el
index 4f24513..f5436c7 100644
--- a/julia-mode-tests.el
+++ b/julia-mode-tests.el
@@ -65,14 +65,37 @@
(font-lock-fontify-buffer)))
(should (eq ,face (get-text-property ,pos 'face)))))
+(defmacro julia--should-move-point (text fun from to &optional end arg)
+ "With TEXT in `julia-mode', after calling FUN, the point should move FROM\
+to TO. If FROM is a string, move the point to matching string before calling
+function FUN. If TO is a string, match resulting point to point a beginning of
+matching line or end of match if END is non-nil. Optional ARG is passed to
FUN."
+ (declare (indent defun))
+ `(with-temp-buffer
+ (julia-mode)
+ (insert ,text)
+ (indent-region (point-min) (point-max))
+ (goto-char (point-min))
+ (if (stringp ,from)
+ (re-search-forward ,from)
+ (goto-char ,from))
+ (funcall ,fun ,arg)
+ (should (eq (point) (if (stringp ,to)
+ (progn (goto-char (point-min))
+ (re-search-forward ,to)
+ (if ,end (goto-char (match-end 0))
+ (goto-char (match-beginning 0))
+ (point-at-bol)))
+ ,to)))))
+
(ert-deftest julia--test-indent-if ()
"We should indent inside if bodies."
(julia--should-indent
- "
+ "
if foo
bar
end"
- "
+ "
if foo
bar
end"))
@@ -80,13 +103,13 @@ end"))
(ert-deftest julia--test-indent-else ()
"We should indent inside else bodies."
(julia--should-indent
- "
+ "
if foo
bar
else
baz
end"
- "
+ "
if foo
bar
else
@@ -96,23 +119,23 @@ end"))
(ert-deftest julia--test-indent-toplevel ()
"We should not indent toplevel expressions. "
(julia--should-indent
- "
+ "
foo()
bar()"
- "
+ "
foo()
bar()"))
(ert-deftest julia--test-indent-nested-if ()
"We should indent for each level of indentation."
(julia--should-indent
- "
+ "
if foo
if bar
bar
end
end"
- "
+ "
if foo
if bar
bar
@@ -151,11 +174,11 @@ end"))
(ert-deftest julia--test-indent-function ()
"We should indent function bodies."
(julia--should-indent
- "
+ "
function foo()
bar
end"
- "
+ "
function foo()
bar
end"))
@@ -163,11 +186,11 @@ end"))
(ert-deftest julia--test-indent-begin ()
"We should indent after a begin keyword."
(julia--should-indent
- "
+ "
@async begin
bar
end"
- "
+ "
@async begin
bar
end"))
@@ -175,10 +198,10 @@ end"))
(ert-deftest julia--test-indent-paren ()
"We should indent to line up with the text after an open paren."
(julia--should-indent
- "
+ "
foobar(bar,
baz)"
- "
+ "
foobar(bar,
baz)"))
@@ -186,31 +209,31 @@ foobar(bar,
"We should indent to line up with the text after an open
paren, even if there are additional spaces."
(julia--should-indent
- "
+ "
foobar( bar,
baz )"
- "
+ "
foobar( bar,
baz )"))
(ert-deftest julia--test-indent-paren-newline ()
"python-mode-like indentation."
(julia--should-indent
- "
+ "
foobar(
bar,
baz)"
- "
+ "
foobar(
bar,
baz)")
(julia--should-indent
- "
+ "
foobar(
bar,
baz
)"
- "
+ "
foobar(
bar,
baz
@@ -219,10 +242,10 @@ foobar(
(ert-deftest julia--test-indent-equals ()
"We should increase indent on a trailing =."
(julia--should-indent
- "
+ "
foo() =
bar"
- "
+ "
foo() =
bar"))
@@ -244,12 +267,12 @@ qux"))
(ert-deftest julia--test-indent-ignores-blank-lines ()
"Blank lines should not affect indentation of non-blank lines."
(julia--should-indent
- "
+ "
if foo
bar
end"
- "
+ "
if foo
bar
@@ -258,11 +281,11 @@ end"))
(ert-deftest julia--test-indent-comment-equal ()
"`=` at the end of comment should not increase indent level."
(julia--should-indent
- "
+ "
# a =
# b =
c"
- "
+ "
# a =
# b =
c"))
@@ -270,32 +293,32 @@ c"))
(ert-deftest julia--test-indent-leading-paren ()
"`(` at the beginning of a line should not affect indentation."
(julia--should-indent
- "
+ "
\(1)"
- "
+ "
\(1)"))
(ert-deftest julia--test-top-level-following-paren-indent ()
"`At the top level, a previous line indented due to parens should not affect
indentation."
(julia--should-indent
- "y1 = f(x,
+ "y1 = f(x,
z)
y2 = g(x)"
- "y1 = f(x,
+ "y1 = f(x,
z)
y2 = g(x)"))
(ert-deftest julia--test-indentation-of-multi-line-strings ()
"Indentation should only affect the first line of a multi-line string."
- (julia--should-indent
- " a = \"\"\"
+ (julia--should-indent
+ " a = \"\"\"
description
begin
foo
bar
end
\"\"\""
- "a = \"\"\"
+ "a = \"\"\"
description
begin
foo
@@ -442,6 +465,136 @@ end")
(julia--should-font-lock string pos font-lock-string-face))
(julia--should-font-lock string (length string) font-lock-keyword-face)))
+;;; Movement
+(ert-deftest julia--test-beginning-of-defun-assn-1 ()
+ "Point moves to beginning of single-line assignment function."
+ (julia--should-move-point
+ "f() = \"a + b\"" 'beginning-of-defun "a \\+" 1))
+
+(ert-deftest julia--test-beginning-of-defun-assn-2 ()
+ "Point moves to beginning of multi-line assignment function."
+ (julia--should-move-point
+ "f(x)=
+x*
+x" 'beginning-of-defun "\\*\nx" 1))
+
+(ert-deftest julia--test-beginning-of-defun-assn-3 ()
+ "Point moves to beginning of multi-line assignment function adjoining
+another function."
+ (julia--should-move-point
+ "f( x
+)::Int16 = x / 2
+f2(y)=
+y*y" 'beginning-of-defun "2" 1))
+
+(ert-deftest julia--test-beginning-of-defun-assn-4 ()
+ "Point moves to beginning of 2nd multi-line assignment function adjoining
+another function."
+ (julia--should-move-point
+ "f( x
+)::Int16 =
+x /
+2
+f2(y) =
+y*y" 'beginning-of-defun "\\*y" "f2"))
+
+(ert-deftest julia--test-beginning-of-defun-assn-5 ()
+ "Point moves to beginning of 1st multi-line assignment function adjoining
+another function with prefix arg."
+ (julia--should-move-point
+ "f( x
+)::Int16 =
+x /
+2
+f2(y) =
+y*y" 'beginning-of-defun "y\\*y" 1 nil 2))
+
+(ert-deftest julia--test-beginning-of-macro ()
+ "Point moves to beginning of macro."
+ (julia--should-move-point
+ "macro current_module()
+return VERSION >= v\"0.7-\" :(@__MODULE__) : :(current_module())))
+end" 'beginning-of-defun "@" 1))
+
+(ert-deftest julia--test-beginning-of-defun-1 ()
+ "Point moves to beginning of defun in 'function's."
+ (julia--should-move-point
+ "function f(a, b)
+a + b
+end" 'beginning-of-defun "f(" 1))
+
+(ert-deftest julia--test-beginning-of-defun-nested-1 ()
+ "Point moves to beginning of nested function."
+ (julia--should-move-point
+ "function f(x)
+
+function fact(n)
+if n == 0
+return 1
+else
+return n * fact(n-1)
+end
+end
+
+return fact(x)
+end" 'beginning-of-defun "fact(n" "function fact"))
+
+(ert-deftest julia--test-beginning-of-defun-nested-2 ()
+ "Point moves to beginning of outermost function with prefix arg."
+ (julia--should-move-point
+ "function f(x)
+
+function fact(n)
+if n == 0
+return 1
+else
+return n * fact(n-1)
+end
+end
+
+return fact(x)
+end" 'beginning-of-defun "n \\*" 1 nil 2))
+
+(ert-deftest julia--test-beginning-of-defun-no-move ()
+ "Point shouldn't move if there is no previous function."
+ (julia--should-move-point
+ "1 + 1
+f(x) = x + 1" 'beginning-of-defun "\\+" 4))
+
+(ert-deftest julia--test-end-of-defun-assn-1 ()
+ "Point should move to end of assignment function."
+ (julia--should-move-point
+ "f(x)::Int8 =
+x *x" 'end-of-defun "(" "*x" 'end))
+
+(ert-deftest julia--test-end-of-defun-nested-1 ()
+ "Point should move to end of inner function when called from inner."
+ (julia--should-move-point
+ "function f(x)
+function fact(n)
+if n == 0
+return 1
+else
+return n * fact(n-1)
+end
+end
+return fact(x)
+end" 'end-of-defun "n == 0" "end[ \n]+end\n" 'end))
+
+(ert-deftest julia--test-end-of-defun-nested-2 ()
+ "Point should move to end of outer function when called from inner with
prefix."
+ (julia--should-move-point
+ "function f(x)
+function fact(n)
+if n == 0
+return 1
+else
+return n * fact(n-1)
+end
+end
+return fact(x)
+end" 'end-of-defun "n == 0" "return fact(x)[ \n]+end" 'end 2))
+
(defun julia--run-tests ()
(interactive)
(if (featurep 'ert)
diff --git a/julia-mode.el b/julia-mode.el
index d7d525a..2bb36f4 100644
--- a/julia-mode.el
+++ b/julia-mode.el
@@ -373,16 +373,16 @@ Based on `python-syntax-stringify'."
(2 ".") ; Don't highlight anything between.
(3 "\""))))) ; Treat the last " in """ as a string delimiter.
-(defun julia-in-comment ()
- "Return non-nil if point is inside a comment.
+(defun julia-in-comment (&optional syntax-ppss)
+ "Return non-nil if point is inside a comment using SYNTAX-PPSS.
Handles both single-line and multi-line comments."
- (nth 4 (syntax-ppss)))
+ (nth 4 (or syntax-ppss (syntax-ppss))))
-(defun julia-in-string ()
- "Return non-nil if point is inside a string.
+(defun julia-in-string (&optional syntax-ppss)
+ "Return non-nil if point is inside a string using SYNTAX-PPSS.
Note this is Emacs' notion of what is highlighted as a string.
As a result, it is true inside \"foo\", `foo` and 'f'."
- (nth 3 (syntax-ppss)))
+ (nth 3 (or syntax-ppss (syntax-ppss))))
(defun julia-in-brackets ()
"Return non-nil if point is inside square brackets."
@@ -637,6 +637,127 @@ meaning always increase indent on TAB and decrease on
S-TAB."
'prog-mode
'fundamental-mode))
+
+;;; Navigation
+;; based off python.el
+(defconst julia-beginning-of-defun-regex
+ (eval-when-compile (concat julia-function-regex "\\|"
+ julia-function-assignment-regex "\\|"
+ "\\_<macro\\_>"))
+ "Regex matching beginning of Julia function or macro.")
+
+(defun julia-syntax-context-type (&optional syntax-ppss)
+ "Return the context type using SYNTAX-PPSS.
+TYPE can be `comment', `string' or `paren'."
+ (let ((ppss (or syntax-ppss (syntax-ppss))))
+ (cond
+ ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string))
+ ((nth 1 ppss) 'paren))))
+
+(defsubst julia-syntax-comment-or-string-p (&optional syntax-ppss)
+ "Return non-nil if SYNTAX-PPSS is inside string or comment."
+ (nth 8 (or syntax-ppss (syntax-ppss))))
+
+(defun julia-looking-at-beginning-of-defun (&optional syntax-ppss)
+ "Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
+ (and (not (julia-syntax-comment-or-string-p (or syntax-ppss (syntax-ppss))))
+ (save-excursion
+ (beginning-of-line 1)
+ (looking-at julia-beginning-of-defun-regex))))
+
+(defun julia--beginning-of-defun (&optional arg)
+ "Internal implementation of `julia-beginning-of-defun'.
+With positive ARG search backwards, else search forwards."
+ (when (or (null arg) (= arg 0)) (setq arg 1))
+ (let* ((re-search-fn (if (> arg 0)
+ #'re-search-backward
+ #'re-search-forward))
+ (line-beg-pos (line-beginning-position))
+ (line-content-start (+ line-beg-pos (current-indentation)))
+ (pos (point-marker))
+ (beg-indentation
+ (and (> arg 0)
+ (save-excursion
+ (while (and (not (julia-looking-at-beginning-of-defun))
+ ;; f(x) = ... function bodies may span multiple
lines
+ (or (and (julia-indent-hanging)
+ (forward-line -1))
+ ;; inside dangling parameter list
+ (and (eq 'paren (julia-syntax-context-type))
+ (backward-up-list))
+ (julia-last-open-block (point-min)))))
+ (or (and (julia-looking-at-beginning-of-defun)
+ (+ (current-indentation) julia-indent-offset))
+ 0))))
+ (found
+ (progn
+ (when (and (< arg 0)
+ (julia-looking-at-beginning-of-defun))
+ (end-of-line 1))
+ (while (and (funcall re-search-fn
+ julia-beginning-of-defun-regex nil t)
+ (or (julia-syntax-comment-or-string-p)
+ ;; handle nested defuns when moving backwards
+ ;; by checking matching indentation
+ (and (> arg 0)
+ (not (= (current-indentation) 0))
+ (>= (current-indentation) beg-indentation)))))
+ (and (julia-looking-at-beginning-of-defun)
+ (or (not (= (line-number-at-pos pos)
+ (line-number-at-pos)))
+ (and (>= (point) line-beg-pos)
+ (<= (point) line-content-start)
+ (> pos line-content-start)))))))
+ (if found
+ (or (beginning-of-line 1) (point))
+ (and (goto-char pos) nil))))
+
+(defun julia-beginning-of-defun (&optional arg)
+ "Move point to `beginning-of-defun'.
+With positive ARG search backwards else search forward.
+ARG nil or 0 defaults to 1. When searching backwards,
+nested defuns are handled depending on current point position.
+Return non-nil (point) if point moved to `beginning-of-defun'."
+ (when (or (null arg) (= arg 0)) (setq arg 1))
+ (let ((found))
+ (while (and (not (= arg 0))
+ (let ((keep-searching-p
+ (julia--beginning-of-defun arg)))
+ (when (and keep-searching-p (null found))
+ (setq found t))
+ keep-searching-p))
+ (setq arg (if (> arg 0) (1- arg) (1+ arg))))
+ found))
+
+(defun julia-end-of-defun (&optional arg)
+ "Move point to the end of the current function.
+Return nil if point is not in a function, otherwise point."
+ (interactive)
+ (let ((beg-defun-indent)
+ (beg-pos (point)))
+ (when (or (julia-looking-at-beginning-of-defun)
+ (julia-beginning-of-defun 1)
+ (julia-beginning-of-defun -1))
+ (beginning-of-line)
+ (if (looking-at-p julia-function-assignment-regex)
+ ;; f(x) = ...
+ (progn
+ ;; skip any dangling lines
+ (while (and (forward-line)
+ (not (eobp))
+ (or (julia-indent-hanging)
+ ;; dangling closing paren
+ (and (eq 'paren (julia-syntax-context-type))
+ (search-forward ")"))))))
+ ;; otherwise skip forward to matching indentation (not in
string/comment)
+ (setq beg-defun-indent (current-indentation))
+ (while (and (not (eobp))
+ (forward-line 1)
+ (or (julia-syntax-comment-or-string-p)
+ (> (current-indentation) beg-defun-indent)))))
+ (end-of-line)
+ (point))))
+
;;; IMENU
(defvar julia-imenu-generic-expression
;; don't use syntax classes, screws egrep
@@ -680,6 +801,8 @@ meaning always increase indent on TAB and decrease on
S-TAB."
(set (make-local-variable 'syntax-propertize-function)
julia-syntax-propertize-function))
(set (make-local-variable 'indent-line-function) 'julia-indent-line)
+ (set (make-local-variable 'beginning-of-defun-function)
#'julia-beginning-of-defun)
+ (set (make-local-variable 'end-of-defun-function) #'julia-end-of-defun)
(setq indent-tabs-mode nil)
(setq imenu-generic-expression julia-imenu-generic-expression)
(imenu-add-to-menubar "Imenu"))
- [nongnu] elpa/julia-mode feb6e79 259/352: Merge pull request #31 from RalphAS/custom-lookback, (continued)
- [nongnu] elpa/julia-mode feb6e79 259/352: Merge pull request #31 from RalphAS/custom-lookback, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode b24410f 279/352: Allow user to set multiple arguments to inferior julia, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 04b97c4 269/352: Merge pull request #37 from tpapp/fix-backslash, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 1f254f8 260/352: Fix indentation for anonymous functions., ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 5812bc3 261/352: Added tests for parentheses following keywords., ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode b99710c 251/352: `python-mode`-like paren-indent, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 483805b 257/352: Merge pull request #29 from nverno/master, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 9f990bb 281/352: Handle string escapes, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 2ef6992 278/352: Fixed import export etc indentation at start of buffer. (#47), ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 117b791 294/352: Replace `Associative` by `AbstractDict` (thanks to @tpapp), ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode dc21978 289/352: Merge pull request #63 from nverno/movement-functions,
ELPA Syncer <=
- [nongnu] elpa/julia-mode 61e22f6 312/352: Merge pull request #90 from tpapp/tp/add-melpa-badge, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode a174d0e 315/352: Fix indentation of generated elisp, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 97325c4 318/352: Merge pull request #87 from tpapp/tp/drop-emacs-23, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 0eec10a 333/352: Do not consider `:end` as block ending, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode c9d8230 329/352: Give \ punctuation syntax outside of strings (#113), ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 6b7e956 321/352: Fix for derived parent mode (#66), ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 9dcabbc 334/352: Simplify the logic to find the end of last block, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 796ddfd 338/352: Apply proper syntax to triple-quoted cmds, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode 505d71b 339/352: Add all problemmatic strings from issue #15 to tests, ELPA Syncer, 2021/08/29
- [nongnu] elpa/julia-mode b800403 326/352: Font lock tweaks (#102), ELPA Syncer, 2021/08/29