aboutsummaryrefslogtreecommitdiffstats
path: root/lib/tools/emacs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tools/emacs')
-rw-r--r--lib/tools/emacs/erlang-eunit.el94
-rw-r--r--lib/tools/emacs/erlang.el168
-rw-r--r--lib/tools/emacs/test.erl.indented5
-rw-r--r--lib/tools/emacs/test.erl.orig5
4 files changed, 174 insertions, 98 deletions
diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el
index b2598f93e6..970afe2e9f 100644
--- a/lib/tools/emacs/erlang-eunit.el
+++ b/lib/tools/emacs/erlang-eunit.el
@@ -102,6 +102,13 @@ buffer and vice versa"
(substring base-name (match-beginning 1) (match-end 1))
base-name)))
+;;; Return the module name of the file
+;;; /tmp/foo/src/x.erl --> x
+;;; /tmp/foo/test/x_tests.erl --> x_tests
+(defun erlang-eunit-module-name (file-path)
+ (interactive)
+ (file-name-sans-extension (file-name-nondirectory file-path)))
+
;;; Return the directory name which is common to both src and test
;;; /tmp/foo/src/x.erl --> /tmp/foo
;;; /tmp/foo/test/x_tests.erl --> /tmp/foo
@@ -128,25 +135,62 @@ buffer and vice versa"
(concat dir file)
(concat dir "/" file)))
-;;; Run EUnit tests for the current module
-(defun erlang-eunit-run-tests ()
- "Run the EUnit test suite for the current module.
+;;; Determine options for EUnit.
+(defun erlang-eunit-opts ()
+ (if current-prefix-arg ", [verbose]" ""))
-With prefix arg, runs tests with the verbose flag set."
- (interactive)
+;;; Determine current test function
+(defun erlang-eunit-test-name ()
+ (save-excursion
+ (erlang-end-of-function 1)
+ (erlang-beginning-of-function 1)
+ (erlang-name-of-function)))
+
+(defun erlang-eunit-simple-test-p (test-name)
+ (if (erlang-eunit-string-match-p "^\\(.+\\)_test$" test-name) t nil))
+
+(defun erlang-eunit-test-generator-p (test-name)
+ (if (erlang-eunit-string-match-p "^\\(.+\\)_test_$" test-name) t nil))
+
+;;; Run the current EUnit test
+(defun erlang-eunit-run-current-test ()
(let* ((module-name (erlang-add-quotes-if-needed
- (erlang-eunit-source-module-name buffer-file-name)))
- (opts (if current-prefix-arg ", [verbose]" ""))
- (command (format "eunit:test(%s%s)." module-name opts)))
+ (erlang-eunit-module-name buffer-file-name)))
+ (test-name (erlang-eunit-test-name))
+ (command
+ (cond ((erlang-eunit-simple-test-p test-name)
+ (format "eunit:test({%s, %s}%s)."
+ module-name test-name (erlang-eunit-opts)))
+ ((erlang-eunit-test-generator-p test-name)
+ (format "eunit:test({generator, %s, %s}%s)."
+ module-name test-name (erlang-eunit-opts)))
+ (t (format "%% WARNING: '%s' is not a test function" test-name)))))
(erlang-eunit-inferior-erlang-send-command command)))
-;;; Compile source and EUnit test file and finally run EUnit tests for
-;;; the current module
-(defun erlang-eunit-compile-and-run-tests ()
- "Compile the source and test files and run the EUnit test suite.
+;;; Run EUnit tests for the current module
+(defun erlang-eunit-run-module-tests ()
+ (let* ((module-name (erlang-add-quotes-if-needed
+ (erlang-eunit-source-module-name buffer-file-name)))
+ (command (format "eunit:test(%s%s)." module-name (erlang-eunit-opts))))
+ (erlang-eunit-inferior-erlang-send-command command)))
+
+(defun erlang-eunit-compile-and-run-current-test ()
+ "Compile the source and test files and run the current EUnit test.
With prefix arg, compiles for debug and runs tests with the verbose flag set."
(interactive)
+ (erlang-eunit-compile-and-test 'erlang-eunit-run-current-test))
+
+(defun erlang-eunit-compile-and-run-module-tests ()
+ "Compile the source and test files and run all EUnit tests in the module.
+
+With prefix arg, compiles for debug and runs tests with the verbose flag set."
+ (interactive)
+ (erlang-eunit-compile-and-test 'erlang-eunit-run-module-tests))
+
+;;; Compile source and EUnit test file and finally run EUnit tests for
+;;; the current module
+(defun erlang-eunit-compile-and-test (run-tests)
(let ((src-filename (erlang-eunit-src-filename buffer-file-name))
(test-filename (erlang-eunit-test-filename buffer-file-name)))
@@ -166,7 +210,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
(if (file-readable-p test-filename)
(erlang-eunit-compile-file test-filename)
t)
- (erlang-eunit-run-tests)))))
+ (funcall run-tests)))))
(defun erlang-eunit-compile-file (file-path)
(if (file-readable-p file-path)
@@ -224,22 +268,18 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
;;; Key bindings
;;;====================================================================
-(defvar erlang-eunit-toggle-src-and-test-file-other-window-key "\C-c\C-et"
- "*Key to which the `erlang-eunit-toggle-src-and-test-file-other-window'
-function will be bound.")
-(defvar erlang-eunit-compile-and-run-tests-key "\C-c\C-ek"
- "*Key to which the `erlang-eunit-compile-and-run-tests'
-function will be bound.")
+(defconst erlang-eunit-key-bindings
+ '(("\C-c\C-et" erlang-eunit-toggle-src-and-test-file-other-window)
+ ("\C-c\C-ek" erlang-eunit-compile-and-run-module-tests)
+ ("\C-c\C-ej" erlang-eunit-compile-and-run-current-test)))
(defun erlang-eunit-add-key-bindings ()
- (erlang-eunit-ensure-keymap-for-key
- erlang-eunit-toggle-src-and-test-file-other-window-key)
- (local-set-key erlang-eunit-toggle-src-and-test-file-other-window-key
- 'erlang-eunit-toggle-src-and-test-file-other-window)
- (erlang-eunit-ensure-keymap-for-key
- erlang-eunit-compile-and-run-tests-key)
- (local-set-key erlang-eunit-compile-and-run-tests-key
- 'erlang-eunit-compile-and-run-tests))
+ (dolist (binding erlang-eunit-key-bindings)
+ (erlang-eunit-bind-key (car binding) (cadr binding))))
+
+(defun erlang-eunit-bind-key (key function)
+ (erlang-eunit-ensure-keymap-for-key key)
+ (local-set-key key function))
(defun erlang-eunit-ensure-keymap-for-key (key-seq)
(let ((prefix-keys (butlast (append key-seq nil)))
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 0132587d28..c31f76025e 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -885,15 +885,54 @@ files written in other languages than Erlang.")
If nil, the inferior shell replaces the window. This is the traditional
behaviour.")
-(defvar erlang-mode-map nil
+(defconst inferior-erlang-use-cmm (boundp 'minor-mode-overriding-map-alist)
+ "Non-nil means use `compilation-minor-mode' in Erlang shell.")
+
+(defvar erlang-mode-map
+ (let ((map (make-sparse-keymap)))
+ (unless (boundp 'indent-line-function)
+ (define-key map "\t" 'erlang-indent-command))
+ (define-key map ";" 'erlang-electric-semicolon)
+ (define-key map "," 'erlang-electric-comma)
+ (define-key map "<" 'erlang-electric-lt)
+ (define-key map ">" 'erlang-electric-gt)
+ (define-key map "\C-m" 'erlang-electric-newline)
+ (if (not (boundp 'delete-key-deletes-forward))
+ (define-key map "\177" 'backward-delete-char-untabify)
+ (define-key map [(backspace)] 'backward-delete-char-untabify))
+ ;;(unless (boundp 'fill-paragraph-function)
+ (define-key map "\M-q" 'erlang-fill-paragraph)
+ (unless (boundp 'beginning-of-defun-function)
+ (define-key map "\M-\C-a" 'erlang-beginning-of-function)
+ (define-key map "\M-\C-e" 'erlang-end-of-function)
+ (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs
+ (define-key map "\M-\t" 'erlang-complete-tag)
+ (define-key map "\C-c\M-\t" 'tempo-complete-tag)
+ (define-key map "\M-+" 'erlang-find-next-tag)
+ (define-key map "\C-c\M-a" 'erlang-beginning-of-clause)
+ (define-key map "\C-c\M-b" 'tempo-backward-mark)
+ (define-key map "\C-c\M-e" 'erlang-end-of-clause)
+ (define-key map "\C-c\M-f" 'tempo-forward-mark)
+ (define-key map "\C-c\M-h" 'erlang-mark-clause)
+ (define-key map "\C-c\C-c" 'comment-region)
+ (define-key map "\C-c\C-j" 'erlang-generate-new-clause)
+ (define-key map "\C-c\C-k" 'erlang-compile)
+ (define-key map "\C-c\C-l" 'erlang-compile-display)
+ (define-key map "\C-c\C-s" 'erlang-show-syntactic-information)
+ (define-key map "\C-c\C-q" 'erlang-indent-function)
+ (define-key map "\C-c\C-u" 'erlang-uncomment-region)
+ (define-key map "\C-c\C-y" 'erlang-clone-arguments)
+ (define-key map "\C-c\C-a" 'erlang-align-arrows)
+ (define-key map "\C-c\C-z" 'erlang-shell-display)
+ (unless inferior-erlang-use-cmm
+ (define-key map "\C-x`" 'erlang-next-error))
+ map)
"*Keymap used in Erlang mode.")
(defvar erlang-mode-abbrev-table nil
"Abbrev table in use in Erlang-mode buffers.")
(defvar erlang-mode-syntax-table nil
"Syntax table in use in Erlang-mode buffers.")
-(defconst inferior-erlang-use-cmm (boundp 'minor-mode-overriding-map-alist)
- "Non-nil means use `compilation-minor-mode' in Erlang shell.")
(defvar erlang-skel-file "erlang-skels"
@@ -1247,7 +1286,7 @@ Other commands:
(setq major-mode 'erlang-mode)
(setq mode-name "Erlang")
(erlang-syntax-table-init)
- (erlang-keymap-init)
+ (use-local-map erlang-mode-map)
(erlang-electric-init)
(erlang-menu-init)
(erlang-mode-variables)
@@ -1302,53 +1341,6 @@ Other commands:
(set-syntax-table erlang-mode-syntax-table))
-(defun erlang-keymap-init ()
- (if erlang-mode-map
- nil
- (setq erlang-mode-map (make-sparse-keymap))
- (erlang-mode-commands erlang-mode-map))
- (use-local-map erlang-mode-map))
-
-
-(defun erlang-mode-commands (map)
- (unless (boundp 'indent-line-function)
- (define-key map "\t" 'erlang-indent-command))
- (define-key map ";" 'erlang-electric-semicolon)
- (define-key map "," 'erlang-electric-comma)
- (define-key map "<" 'erlang-electric-lt)
- (define-key map ">" 'erlang-electric-gt)
- (define-key map "\C-m" 'erlang-electric-newline)
- (if (not (boundp 'delete-key-deletes-forward))
- (define-key map "\177" 'backward-delete-char-untabify)
- (define-key map [(backspace)] 'backward-delete-char-untabify))
- ;;(unless (boundp 'fill-paragraph-function)
- (define-key map "\M-q" 'erlang-fill-paragraph)
- (unless (boundp 'beginning-of-defun-function)
- (define-key map "\M-\C-a" 'erlang-beginning-of-function)
- (define-key map "\M-\C-e" 'erlang-end-of-function)
- (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs
- (define-key map "\M-\t" 'erlang-complete-tag)
- (define-key map "\C-c\M-\t" 'tempo-complete-tag)
- (define-key map "\M-+" 'erlang-find-next-tag)
- (define-key map "\C-c\M-a" 'erlang-beginning-of-clause)
- (define-key map "\C-c\M-b" 'tempo-backward-mark)
- (define-key map "\C-c\M-e" 'erlang-end-of-clause)
- (define-key map "\C-c\M-f" 'tempo-forward-mark)
- (define-key map "\C-c\M-h" 'erlang-mark-clause)
- (define-key map "\C-c\C-c" 'comment-region)
- (define-key map "\C-c\C-j" 'erlang-generate-new-clause)
- (define-key map "\C-c\C-k" 'erlang-compile)
- (define-key map "\C-c\C-l" 'erlang-compile-display)
- (define-key map "\C-c\C-s" 'erlang-show-syntactic-information)
- (define-key map "\C-c\C-q" 'erlang-indent-function)
- (define-key map "\C-c\C-u" 'erlang-uncomment-region)
- (define-key map "\C-c\C-y" 'erlang-clone-arguments)
- (define-key map "\C-c\C-a" 'erlang-align-arrows)
- (define-key map "\C-c\C-z" 'erlang-shell-display)
- (unless inferior-erlang-use-cmm
- (define-key map "\C-x`" 'erlang-next-error)))
-
-
(defun erlang-electric-init ()
;; Set up electric character functions to work with
;; delsel/pending-del mode. Also, set up text properties for bit
@@ -1402,7 +1394,7 @@ Other commands:
(set (make-local-variable 'imenu-prev-index-position-function)
'erlang-beginning-of-function)
(set (make-local-variable 'imenu-extract-index-name-function)
- 'erlang-get-function-name)
+ 'erlang-get-function-name-and-arity)
(set (make-local-variable 'tempo-match-finder)
"[^-a-zA-Z0-9_]\\([-a-zA-Z0-9_]*\\)\\=")
(set (make-local-variable 'beginning-of-defun-function)
@@ -2933,10 +2925,16 @@ This assumes that the preceding expression is either simple
(skip-chars-backward " \t")
;; Needed to match the colon in "'foo':'bar'".
(if (not (memq (preceding-char) '(?# ?:)))
- col
- (backward-char 1)
- (forward-sexp -1)
- (current-column)))))
+ col
+ ;; Special hack to handle: (note line break)
+ ;; [#myrecord{
+ ;; foo = foo}]
+ (or
+ (ignore-errors
+ (backward-char 1)
+ (forward-sexp -1)
+ (current-column))
+ col)))))
(defun erlang-indent-parenthesis (stack-position)
(let ((previous (erlang-indent-find-preceding-expr)))
@@ -3505,6 +3503,13 @@ Normally used in conjunction with `erlang-beginning-of-clause', e.g.:
res)
(error nil)))))
+(defun erlang-get-function-name-and-arity ()
+ "Return the name and arity of the function at point, or nil.
+The return value is a string of the form \"foo/1\"."
+ (let ((name (erlang-get-function-name))
+ (arity (erlang-get-function-arity)))
+ (and name arity (format "%s/%d" name arity))))
+
(defun erlang-get-function-arguments ()
"Return arguments of current function, or nil."
(if (not (looking-at (eval-when-compile
@@ -4901,9 +4906,14 @@ a prompt. When nil, we will wait forever, or until \\[keyboard-quit].")
(defvar inferior-erlang-buffer nil
"Buffer of last invoked inferior Erlang, or nil.")
+;; Enable uniquifying Erlang shell buffers based on directory name.
+(eval-after-load "uniquify"
+ '(add-to-list 'uniquify-list-buffers-directory-modes 'erlang-shell-mode))
+
;;;###autoload
-(defun inferior-erlang ()
+(defun inferior-erlang (&optional command)
"Run an inferior Erlang.
+With prefix command, prompt for command to start Erlang with.
This is just like running Erlang in a normal shell, except that
an Emacs buffer is used for input and output.
@@ -4917,17 +4927,37 @@ Entry to this mode calls the functions in the variables
The following commands imitate the usual Unix interrupt and
editing control characters:
\\{erlang-shell-mode-map}"
- (interactive)
+ (interactive
+ (when current-prefix-arg
+ (list (if (fboundp 'read-shell-command)
+ ;; `read-shell-command' is a new function in Emacs 23.
+ (read-shell-command "Erlang command: ")
+ (read-string "Erlang command: ")))))
(require 'comint)
- (let ((opts inferior-erlang-machine-options))
- (cond ((eq inferior-erlang-shell-type 'oldshell)
- (setq opts (cons "-oldshell" opts)))
- ((eq inferior-erlang-shell-type 'newshell)
- (setq opts (append '("-newshell" "-env" "TERM" "vt100") opts))))
- (setq inferior-erlang-buffer
- (apply 'make-comint
- inferior-erlang-process-name inferior-erlang-machine
- nil opts)))
+ (let (cmd opts)
+ (if command
+ (setq cmd "sh"
+ opts (list "-c" command))
+ (setq cmd inferior-erlang-machine
+ opts inferior-erlang-machine-options)
+ (cond ((eq inferior-erlang-shell-type 'oldshell)
+ (setq opts (cons "-oldshell" opts)))
+ ((eq inferior-erlang-shell-type 'newshell)
+ (setq opts (append '("-newshell" "-env" "TERM" "vt100") opts)))))
+
+ ;; Using create-file-buffer and list-buffers-directory in this way
+ ;; makes uniquify give each buffer a unique name based on the
+ ;; directory.
+ (let ((fake-file-name (expand-file-name inferior-erlang-buffer-name default-directory)))
+ (setq inferior-erlang-buffer (create-file-buffer fake-file-name))
+ (apply 'make-comint-in-buffer
+ inferior-erlang-process-name
+ inferior-erlang-buffer
+ cmd
+ nil opts)
+ (with-current-buffer inferior-erlang-buffer
+ (setq list-buffers-directory fake-file-name))))
+
(setq inferior-erlang-process
(get-buffer-process inferior-erlang-buffer))
(if (> 21 erlang-emacs-major-version) ; funcalls to avoid compiler warnings
@@ -4940,10 +4970,6 @@ editing control characters:
(if (and (not (eq system-type 'windows-nt))
(eq inferior-erlang-shell-type 'newshell))
(setq comint-process-echoes t))
- ;; `rename-buffer' takes only one argument in Emacs 18.
- (condition-case nil
- (rename-buffer inferior-erlang-buffer-name t)
- (error (rename-buffer inferior-erlang-buffer-name)))
(erlang-shell-mode))
diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented
index d0ea4c29cf..1dc976d8dc 100644
--- a/lib/tools/emacs/test.erl.indented
+++ b/lib/tools/emacs/test.erl.indented
@@ -588,3 +588,8 @@ indent_comprehensions() ->
true = (X rem 2)
>>,
ok.
+
+%% This causes an error in earlier erlang-mode versions.
+foo() ->
+ [#foo{
+ foo = foo}].
diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig
index 70e97a2e91..feb9e4e5a1 100644
--- a/lib/tools/emacs/test.erl.orig
+++ b/lib/tools/emacs/test.erl.orig
@@ -588,3 +588,8 @@ Binary2 = << <<X:8>> || <<X:32,_:32>> <= <<0:512>>,
true = (X rem 2)
>>,
ok.
+
+%% This causes an error in earlier erlang-mode versions.
+foo() ->
+[#foo{
+foo = foo}].