emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/julia-mode 10b0eff 286/352: beginning/end of defun functio


From: ELPA Syncer
Subject: [nongnu] elpa/julia-mode 10b0eff 286/352: beginning/end of defun functions
Date: Sun, 29 Aug 2021 11:23:03 -0400 (EDT)

branch: elpa/julia-mode
commit 10b0eff520eab0248b3687be3b4125dd743c47cf
Author: nverno <noah.v.peart@gmail.com>
Commit: nverno <noah.v.peart@gmail.com>

    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 4e5960c..ff4d7d8 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"))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]