From 7903bfe91132ee931f68c61b4097462480c824c7 Mon Sep 17 00:00:00 2001 From: abicky Date: Sat, 15 Sep 2018 14:25:44 +0900 Subject: [PATCH 1/9] End support of Node.js versions whose stauts is end-of-life cf. https://github.com/nodejs/Release --- .travis.yml | 9 ++------- nodejs-repl.el | 22 +++------------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/.travis.yml b/.travis.yml index ad66de3..23059bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,8 @@ language: node_js node_js: - - "0.6" - - "0.8" - - "0.10" - - "0.12" - - "4" - - "5" - "6" - - "node" + - "8" + - "10" env: - EVM_EMACS=emacs-24.1-travis diff --git a/nodejs-repl.el b/nodejs-repl.el index f111ac8..330c38a 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -110,14 +110,8 @@ See also `comint-process-echoes'" (define-key map (kbd "C-c C-c") 'nodejs-repl-quit-or-cancel) map)) -;; process.stdout.columns should be set. -;; Node.js 0.8 and 0.10 uses this value as the maximum number of columns, -;; but process.stdout.columns in Emacs is infinity because Emacs returns 0 as winsize.ws_col. -;; The completion candidates won't be displayed if process.stdout.columns is infinity. -;; see also `handleGroup` function in readline.js (defvar nodejs-repl-code-format (concat - "process.stdout.columns = %d;" "require('repl').start('%s', null, null, true, false, " "require('repl')['REPL_MODE_' + '%s'.toUpperCase()])")) @@ -127,14 +121,7 @@ See also `comint-process-echoes'" ;;; if send string like "a; Ma\t", return a; Math\x1b[1G> a; Math\x1b[0K\x1b[10G (defvar nodejs-repl-prompt-re-format - (concat - "\x1b\\[1G" - "\\(" - "\x1b\\[0J%s.*\x1b\\[[0-9]+G.*" ; for Node.js 0.8 - "\\|" - "%s.*\x1b\\[0K\x1b\\[[0-9]+G.*" ; for Node.js 0.4 or 0.6 - "\\)" - "$")) + "\x1b\\[1G\x1b\\[0J%s.*\x1b\\[[0-9]+G.*$") (defvar nodejs-repl-prompt-re (format nodejs-repl-prompt-re-format nodejs-repl-prompt nodejs-repl-prompt)) ;;; not support Unicode characters @@ -207,7 +194,6 @@ See also `comint-process-echoes'" (not (let ((last-line (process-get proc 'last-line))) (or (string-match-p nodejs-repl-prompt-re last-line) - (string-match-p "^\x1b[[0-9]+D$" last-line) ; for Node.js 0.8 (string= last-line string))))) (process-put proc 'running-p nil) (accept-process-output proc interval))) @@ -461,9 +447,7 @@ otherwise spawn one." (string-match-p (concat "^" nodejs-repl-cache-token) token) (not (string-match-p (concat "^" nodejs-repl-cache-token ".*?[.(/'\"]") token))) (setq candidates nodejs-repl-cache-candidates) - (if (equal token "require(") ; a bug occurs when press TAB after "require(" in node 0.6 - (setq candidates nil) - (setq candidates (nodejs-repl--get-candidates-from-process token))) + (setq candidates (nodejs-repl--get-candidates-from-process token)) (setq nodejs-repl-cache-token token) (setq nodejs-repl-cache-candidates candidates)) candidates)) @@ -496,7 +480,7 @@ otherwise spawn one." (shell-command-to-string (concat nodejs-repl-command " --version")))) (let* ((repl-mode (or (getenv "NODE_REPL_MODE") "magic")) (nodejs-repl-code (format nodejs-repl-code-format - (window-width) nodejs-repl-prompt repl-mode ))) + nodejs-repl-prompt repl-mode))) (pop-to-buffer (apply 'make-comint nodejs-repl-process-name nodejs-repl-command nil `(,@nodejs-repl-arguments "-e" ,nodejs-repl-code))) From 08d115f456cca3816315b3f7e8b314539fecaf4a Mon Sep 17 00:00:00 2001 From: abicky Date: Sun, 16 Sep 2018 05:11:48 +0900 Subject: [PATCH 2/9] End support of old Emacs versions --- .travis.yml | 7 ++- nodejs-repl.el | 113 +++++++++++++++++++++++++------------------------ test/test.el | 31 ++++++++------ 3 files changed, 79 insertions(+), 72 deletions(-) diff --git a/.travis.yml b/.travis.yml index 23059bf..3c0fcd0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,11 @@ node_js: - "10" env: - - EVM_EMACS=emacs-24.1-travis - - EVM_EMACS=emacs-24.2-travis - - EVM_EMACS=emacs-24.3-travis - - EVM_EMACS=emacs-24.4-travis - EVM_EMACS=emacs-24.5-travis - EVM_EMACS=emacs-25.1-travis + - EVM_EMACS=emacs-25.2-travis + - EVM_EMACS=emacs-25.3-travis + - EVM_EMACS=emacs-26.1-travis before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh diff --git a/nodejs-repl.el b/nodejs-repl.el index 330c38a..5b5d71f 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -106,7 +106,7 @@ See also `comint-process-echoes'" (defvar nodejs-repl-mode-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "TAB") 'comint-dynamic-complete) + (define-key map (kbd "TAB") 'completion-at-point) (define-key map (kbd "C-c C-c") 'nodejs-repl-quit-or-cancel) map)) @@ -140,8 +140,9 @@ See also `comint-process-echoes'" '(! + - void typeof delete)) (defvar nodejs-repl-cache-token "") -(defvar nodejs-repl-cache-candidates ()) +(defvar nodejs-repl-cache-completions ()) +(defvar nodejs-repl-get-completions-for-require-p nil) ;;;-------------------------- ;;; Private functions @@ -207,13 +208,13 @@ when receive the output string" (goto-char (point-max)) (process-put proc 'last-line (buffer-substring (point-at-bol) (point))))) -(defun nodejs-repl--get-candidates-from-process (token) - "Get completion candidates sending TAB to Node.js process." +(defun nodejs-repl--get-completions-from-process (token) + "Get completions sending TAB to Node.js process." (let ((ret (if (version< nodejs-repl-nodejs-version "7.0.0") (nodejs-repl--send-string (concat token "\t")) (nodejs-repl--send-string (concat token "\t")) (nodejs-repl--send-string "\t"))) - candidates) + completions) (nodejs-repl-clear-line) (when (not (equal ret token)) (if (string-match-p "\n" ret) @@ -225,21 +226,21 @@ when receive the output string" ;; trim trailing whitespaces (setq ret (replace-regexp-in-string "[ \t\r\n]*\\'" "" ret)) ;; don't split by whitespaces because the prompt might have whitespaces!! - (setq candidates (split-string ret "\n")) + (setq completions (split-string ret "\n")) ;; remove the first element (input) and the last element (prompt) - (setq candidates (reverse (cdr (reverse (cdr candidates))))) + (setq completions (reverse (cdr (reverse (cdr completions))))) ;; split by whitespaces ;; '("encodeURI encodeURIComponent") -> '("encodeURI" "encodeURIComponent") - (setq candidates (split-string - (replace-regexp-in-string " *$" "" (mapconcat 'identity candidates " ")) + (setq completions (split-string + (replace-regexp-in-string " *$" "" (mapconcat 'identity completions " ")) "[ \t\r\n]+")) ) (setq ret (replace-regexp-in-string nodejs-repl-extra-espace-sequence-re "" ret)) (let ((candidate-token (nodejs-repl--get-last-token ret))) - (setq candidates (if (or (null candidate-token) (equal candidate-token token)) + (setq completions (if (or (null candidate-token) (equal candidate-token token)) nil (list candidate-token)))))) - candidates)) + completions)) (defun nodejs-repl--get-or-create-process () (let ((proc (get-process nodejs-repl-process-name))) @@ -262,7 +263,7 @@ when receive the output string" (defun nodejs-repl--clear-cache (string) "Clear caches when outputting the result." (setq nodejs-repl-cache-token "") - (setq nodejs-repl-cache-candidates ())) + (setq nodejs-repl-cache-completions ())) (defun nodejs-repl--remove-duplicated-prompt (string) ;; `.load` command of Node.js repl outputs a duplicated prompt @@ -330,6 +331,50 @@ when receive the output string" (t (error "No proper expression is found backward")))) +(defun nodejs-repl--completion-at-point-function () + (when (comint-after-pmark-p) + (let* ((input (buffer-substring (comint-line-beginning-position) (point))) + require-arg + token-length + file-completion-p) + (setq nodejs-repl-get-completions-for-require-p nil) ;; reset + (if (not (nodejs-repl--in-string-p)) + (setq token-length (length (nodejs-repl--get-last-token input))) + (setq require-arg (nodejs-repl--extract-require-argument input) + nodejs-repl-get-completions-for-require-p t) + (if (and require-arg + (or (= (length require-arg) 1) ; only quote or double quote + (not (string-match-p "[./]" (substring require-arg 1 2))))) ; not file path + (setq token-length (1- (length require-arg))) + (let ((quote-pos (save-excursion + (search-backward-regexp "['\"]" (point-at-bol) t) + (forward-char) + (point)))) + (when quote-pos + (setq file-completion-p t + token-length (- (point) quote-pos)))))) + (when token-length + (list + (save-excursion (backward-char token-length) (point)) + (point) + (if file-completion-p + #'completion-file-name-table + (completion-table-dynamic #'nodejs-repl--get-completions))))))) + +(defun nodejs-repl--get-completions (token) + (let (completions) + (when nodejs-repl-get-completions-for-require-p + (setq token (concat "require('" token))) + (if (and (not (equal nodejs-repl-cache-token "")) + (string-prefix-p nodejs-repl-cache-token token) + (not (string-match-p (concat "^" nodejs-repl-cache-token ".*?[.(/'\"]") token))) + (setq completions nodejs-repl-cache-completions) + (setq completions (nodejs-repl--get-completions-from-process token) + nodejs-repl-cache-token token + nodejs-repl-cache-completions completions)) + completions)) + + ;;;-------------------------- ;;; Public functions ;;;-------------------------- @@ -414,45 +459,6 @@ otherwise spawn one." (goto-char (point-max)) (delete-region (point-at-bol) (point))))) -(defun nodejs-repl-complete-from-process () - "Dynamically complete tokens at the point." - (when (comint-after-pmark-p) - (let* ((input (buffer-substring (comint-line-beginning-position) (point))) - require-arg - token - candidates - ret) - (if (nodejs-repl--in-string-p) - (progn - (setq require-arg (nodejs-repl--extract-require-argument input)) - (if (and require-arg - (or (= (length require-arg) 1) - (not (string-match-p "[./]" (substring require-arg 1 2))))) - (setq token (concat "require(" require-arg)) - (setq ret (comint-dynamic-complete-as-filename)))) - (setq token (nodejs-repl--get-last-token input))) - (when token - (setq candidates (nodejs-repl-get-candidates token)) - ;; TODO: write unit test - (setq token (replace-regexp-in-string "^require(['\"]" "" token)) - (setq ret (comint-dynamic-simple-complete token candidates))) - (if (eq ret 'sole) - (delete-char -1)) - ret))) - -(defun nodejs-repl-get-candidates (token) - "Get completion candidates." - (let (candidates) - (if (and (not (equal nodejs-repl-cache-token "")) - (string-match-p (concat "^" nodejs-repl-cache-token) token) - (not (string-match-p (concat "^" nodejs-repl-cache-token ".*?[.(/'\"]") token))) - (setq candidates nodejs-repl-cache-candidates) - (setq candidates (nodejs-repl--get-candidates-from-process token)) - (setq nodejs-repl-cache-token token) - (setq nodejs-repl-cache-candidates candidates)) - candidates)) - - (define-derived-mode nodejs-repl-mode comint-mode "Node.js REPL" "Major mode for Node.js REPL" :syntax-table nodejs-repl-mode-syntax-table @@ -462,10 +468,7 @@ otherwise spawn one." (add-hook 'comint-output-filter-functions 'nodejs-repl--clear-cache nil t) (setq comint-input-ignoredups nodejs-repl-input-ignoredups) (setq comint-process-echoes nodejs-repl-process-echoes) - ;; delq seems to change global variables if called this phase - (set (make-local-variable 'comint-dynamic-complete-functions) - (delete 'comint-dynamic-complete-filename comint-dynamic-complete-functions)) - (add-hook 'comint-dynamic-complete-functions 'nodejs-repl-complete-from-process nil t) + (add-hook 'completion-at-point-functions 'nodejs-repl--completion-at-point-function nil t) (ansi-color-for-comint-mode-on)) ;;;###autoload diff --git a/test/test.el b/test/test.el index 248fdd3..09eb713 100644 --- a/test/test.el +++ b/test/test.el @@ -46,31 +46,36 @@ ;; node 0.6.17 outputs "undefined" (string-match-p "a\n\nb\n\\(undefined\\)?" (buffer-string)))) - (desc "nodejs-repl-get-candidates") + (desc "nodejs-repl--get-completions") (expect '("Error") - (delete-dups (nodejs-repl-get-candidates "Err"))) + (delete-dups (nodejs-repl--get-completions "Err"))) (expect '("Error") - (delete-dups (nodejs-repl-get-candidates "Erro"))) + (delete-dups (nodejs-repl--get-completions "Erro"))) (expect "Err" ; use cache? nodejs-repl-cache-token) (expect '("Math.max" "Math.min") - (nodejs-repl-get-candidates "Math.m")) + (nodejs-repl--get-completions "Math.m")) ;; FIXME: this test is meaningless if window width is not set (expect '("encodeURI" "encodeURIComponent") - (delete-dups (nodejs-repl-get-candidates "encode"))) + (delete-dups (nodejs-repl--get-completions "encode"))) - (desc "nodejs-repl-get-candidates for require") + (desc "nodejs-repl--get-completions for require") (expect nil - (nodejs-repl-get-candidates "foo")) + (nodejs-repl--get-completions "foo")) (expect '("require") - (nodejs-repl-get-candidates "requi")) + (nodejs-repl--get-completions "requi")) (expect t - (nodejs-repl-get-candidates "require(") ; update cache - (> (length (nodejs-repl-get-candidates "require(\"")) 1)) - (expect "require(\"" ; update cache? + (> (length (let ((nodejs-repl-get-completions-for-require-p t)) + (nodejs-repl--get-completions ""))) 1)) + (expect "require('" ; update cache? nodejs-repl-cache-token) - (expect "require(\"npm/" ; update cache? - (nodejs-repl-get-candidates "require(\"npm/") + (expect "require('" ; use cache? + (let ((nodejs-repl-get-completions-for-require-p t)) + (nodejs-repl--get-completions "f")) + nodejs-repl-cache-token) + (expect "require('npm/" ; update cache? + (let ((nodejs-repl-get-completions-for-require-p t)) + (nodejs-repl--get-completions "npm/")) nodejs-repl-cache-token) (desc "nodejs-repl--extract-require-argument") From 42d725ea0827feefb5bea96cb9f8b75aa0dd2f8b Mon Sep 17 00:00:00 2001 From: abicky Date: Sun, 16 Sep 2018 05:19:59 +0900 Subject: [PATCH 3/9] Remove unexpected prompts --- nodejs-repl.el | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nodejs-repl.el b/nodejs-repl.el index 5b5d71f..b1091a8 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -143,6 +143,7 @@ See also `comint-process-echoes'" (defvar nodejs-repl-cache-completions ()) (defvar nodejs-repl-get-completions-for-require-p nil) +(defvar nodejs-repl-completion-at-point-called-p nil) ;;;-------------------------- ;;; Private functions @@ -275,6 +276,18 @@ when receive the output string" (when (re-search-forward (concat nodejs-repl-prompt nodejs-repl-prompt) end t) (replace-match nodejs-repl-prompt))))) +(defun nodejs-repl--remove-unexpected-prompts (string) + ;; Unexpected prompts are inserted if `completion-auto-help' is t + (when nodejs-repl-completion-at-point-called-p + (setq nodejs-repl-completion-at-point-called-p nil) + (let ((beg (or comint-last-output-start + (point-min-marker))) + (end (process-mark (get-buffer-process (current-buffer))))) + (save-excursion + (goto-char beg) + (when (re-search-forward nodejs-repl-prompt end t) + (replace-match "")))))) + ;; cf. https://www.ecma-international.org/ecma-262/#sec-ecmascript-language-expressions (defun nodejs-repl--beginning-of-expression () (search-backward-regexp "[[:graph:]]" nil t) @@ -332,6 +345,7 @@ when receive the output string" (error "No proper expression is found backward")))) (defun nodejs-repl--completion-at-point-function () + (setq nodejs-repl-completion-at-point-called-p t) (when (comint-after-pmark-p) (let* ((input (buffer-substring (comint-line-beginning-position) (point))) require-arg @@ -463,6 +477,7 @@ otherwise spawn one." "Major mode for Node.js REPL" :syntax-table nodejs-repl-mode-syntax-table (set (make-local-variable 'font-lock-defaults) '(nil nil t)) + (add-hook 'comint-output-filter-functions 'nodejs-repl--remove-unexpected-prompts nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--remove-duplicated-prompt nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--filter-escape-sequnces nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--clear-cache nil t) From c4dd56abf0e464435747cc7f59c72855fc44ea45 Mon Sep 17 00:00:00 2001 From: abicky Date: Sun, 16 Sep 2018 08:12:10 +0900 Subject: [PATCH 4/9] Exclude some combinations which fail only in Travis CI --- .travis.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c0fcd0..fe24466 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: node_js node_js: - - "6" - - "8" - - "10" + - 6 + - 8 + - 10 env: - EVM_EMACS=emacs-24.5-travis @@ -11,6 +11,17 @@ env: - EVM_EMACS=emacs-25.3-travis - EVM_EMACS=emacs-26.1-travis +matrix: + exclude: + - node_js: 6 + env: EVM_EMACS=emacs-25.1-travis + - node_js: 6 + env: EVM_EMACS=emacs-25.2-travis + - node_js: 6 + env: EVM_EMACS=emacs-25.3-travis + - node_js: 6 + env: EVM_EMACS=emacs-26.1-travis + before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh - evm install $EVM_EMACS --use --skip From 6c49fe54a0040bcb4a93f393e7e9f3eea8e75ce1 Mon Sep 17 00:00:00 2001 From: Jiangbin Zhao Date: Wed, 5 Sep 2018 21:54:29 -0700 Subject: [PATCH 5/9] Add support for path to Node.js command per project. If the variable `nodejs-repl-command' is a function symbol, call the function for the path. --- README.md | 19 +++++++++++++++++++ nodejs-repl.el | 35 +++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ec06c29..8ce4f42 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,25 @@ You can define key bindings to send JavaScript codes to REPL like below: (define-key js-mode-map (kbd "C-c C-l") 'nodejs-repl-load-file) (define-key js-mode-map (kbd "C-c C-z") 'nodejs-repl-switch-to-repl))) +When a version manager such as nvm is used to run different versions +of Node.js, it is often desirable to start the REPL of the version +specified in the .nvmrc file per project. In such case, customize the +`nodejs-repl-command` variable with a function symbol. That function +should query nvm for the Node.js command to run. For example: + + (require 'nodejs-repl) + (defun nvm-which () + (let* ((shell (concat (getenv "SHELL") " -l -c 'nvm which'")) + (output (shell-command-to-string shell))) + (cadr (split-string output "[\n]+" t)))) + (setq nodejs-repl-command #'nvm-which) + +The `nvm-which` function can be simpler, and perhaps can run faster, +too, if using Bash: + + (defun nvm-which () + (let ((output (shell-command-to-string "source ~/.nvm/nvm.sh; nvm which"))) + (cadr (split-string output "[\n]+" t)))) Author ------ diff --git a/nodejs-repl.el b/nodejs-repl.el index b1091a8..48875d2 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -57,7 +57,10 @@ "Node.js mode Version.") (defcustom nodejs-repl-command "node" - "Node.js command used in `nodejs-repl-mode'." + "Node.js command used in `nodejs-repl-mode'. If it is a symbol +of a function, the function is called for the path of the Node.js +command. This allows to integrate with a Node.js version manager +such as nvm." :group 'nodejs-repl :type 'string) @@ -490,19 +493,23 @@ otherwise spawn one." (defun nodejs-repl () "Run Node.js REPL." (interactive) - (setq nodejs-repl-prompt-re - (format nodejs-repl-prompt-re-format nodejs-repl-prompt nodejs-repl-prompt)) - (setq nodejs-repl-nodejs-version - ;; "v7.3.0" => "7.3.0", "v7.x-dev" => "7" - (replace-regexp-in-string nodejs-repl--nodejs-version-re "\\1" - (shell-command-to-string (concat nodejs-repl-command " --version")))) - (let* ((repl-mode (or (getenv "NODE_REPL_MODE") "magic")) - (nodejs-repl-code (format nodejs-repl-code-format - nodejs-repl-prompt repl-mode))) - (pop-to-buffer - (apply 'make-comint nodejs-repl-process-name nodejs-repl-command nil - `(,@nodejs-repl-arguments "-e" ,nodejs-repl-code))) - (nodejs-repl-mode))) + (let ((node-command (if (and (symbolp nodejs-repl-command) + (functionp nodejs-repl-command)) + (funcall nodejs-repl-command) + nodejs-repl-command))) + (setq nodejs-repl-prompt-re + (format nodejs-repl-prompt-re-format nodejs-repl-prompt nodejs-repl-prompt)) + (setq nodejs-repl-nodejs-version + ;; "v7.3.0" => "7.3.0", "v7.x-dev" => "7" + (replace-regexp-in-string nodejs-repl--nodejs-version-re "\\1" + (shell-command-to-string (concat node-command " --version")))) + (let* ((repl-mode (or (getenv "NODE_REPL_MODE") "magic")) + (nodejs-repl-code (format nodejs-repl-code-format + nodejs-repl-prompt repl-mode ))) + (pop-to-buffer + (apply 'make-comint nodejs-repl-process-name node-command nil + `(,@nodejs-repl-arguments "-e" ,nodejs-repl-code))) + (nodejs-repl-mode)))) (provide 'nodejs-repl) ;;; nodejs-repl.el ends here From 0820db25833232b7126e8ab8935598a103415c58 Mon Sep 17 00:00:00 2001 From: abicky Date: Tue, 18 Sep 2018 01:23:22 +0900 Subject: [PATCH 6/9] Delete prompts inserted on set_window_size This PR resolves https://github.com/abicky/nodejs-repl.el/issues/15. --- nodejs-repl.el | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/nodejs-repl.el b/nodejs-repl.el index 48875d2..d0e57e9 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -146,7 +146,7 @@ See also `comint-process-echoes'" (defvar nodejs-repl-cache-completions ()) (defvar nodejs-repl-get-completions-for-require-p nil) -(defvar nodejs-repl-completion-at-point-called-p nil) +(defvar nodejs-repl-prompt-deletion-required-p nil) ;;;-------------------------- ;;; Private functions @@ -269,6 +269,9 @@ when receive the output string" (setq nodejs-repl-cache-token "") (setq nodejs-repl-cache-completions ())) +(defun nodejs-repl--set-prompt-deletion-required-p () + (setq nodejs-repl-prompt-deletion-required-p t)) + (defun nodejs-repl--remove-duplicated-prompt (string) ;; `.load` command of Node.js repl outputs a duplicated prompt (let ((beg (or comint-last-output-start @@ -279,10 +282,10 @@ when receive the output string" (when (re-search-forward (concat nodejs-repl-prompt nodejs-repl-prompt) end t) (replace-match nodejs-repl-prompt))))) -(defun nodejs-repl--remove-unexpected-prompts (string) - ;; Unexpected prompts are inserted if `completion-auto-help' is t - (when nodejs-repl-completion-at-point-called-p - (setq nodejs-repl-completion-at-point-called-p nil) +(defun nodejs-repl--delete-prompt (string) + ;; A prompt will be inserted if window--adjust-process-windows is called + (when nodejs-repl-prompt-deletion-required-p + (setq nodejs-repl-prompt-deletion-required-p nil) (let ((beg (or comint-last-output-start (point-min-marker))) (end (process-mark (get-buffer-process (current-buffer))))) @@ -480,13 +483,15 @@ otherwise spawn one." "Major mode for Node.js REPL" :syntax-table nodejs-repl-mode-syntax-table (set (make-local-variable 'font-lock-defaults) '(nil nil t)) - (add-hook 'comint-output-filter-functions 'nodejs-repl--remove-unexpected-prompts nil t) + (add-hook 'comint-output-filter-functions 'nodejs-repl--delete-prompt nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--remove-duplicated-prompt nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--filter-escape-sequnces nil t) (add-hook 'comint-output-filter-functions 'nodejs-repl--clear-cache nil t) (setq comint-input-ignoredups nodejs-repl-input-ignoredups) (setq comint-process-echoes nodejs-repl-process-echoes) (add-hook 'completion-at-point-functions 'nodejs-repl--completion-at-point-function nil t) + (make-local-variable 'window-configuration-change-hook) + (add-hook 'window-configuration-change-hook 'nodejs-repl--set-prompt-deletion-required-p) (ansi-color-for-comint-mode-on)) ;;;###autoload From 8a21bb54087d6e5004bdcde79dfd13ce53f1f357 Mon Sep 17 00:00:00 2001 From: abicky Date: Tue, 18 Sep 2018 01:27:51 +0900 Subject: [PATCH 7/9] Remove nodejs-repl-send-last-sexp --- nodejs-repl.el | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nodejs-repl.el b/nodejs-repl.el index 48875d2..4f15690 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -450,10 +450,6 @@ when receive the output string" (nodejs-repl-send-region (save-excursion (nodejs-repl--beginning-of-expression)) (point))) -;;;###autoload -(defun nodejs-repl-send-last-sexp () (interactive)) ;; Dummy definition for autoload -(define-obsolete-function-alias 'nodejs-repl-send-last-sexp 'nodejs-repl-send-last-expression) - ;;;###autoload (defun nodejs-repl-switch-to-repl () "If there is a `nodejs-repl-process' running switch to it, From d38211fa53b687017475ea2a9f58ee351f9d3843 Mon Sep 17 00:00:00 2001 From: abicky Date: Tue, 18 Sep 2018 01:55:05 +0900 Subject: [PATCH 8/9] Bump the version number to 0.2.0 --- nodejs-repl.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs-repl.el b/nodejs-repl.el index e4bb402..9a16def 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2012-2017 Takeshi Arabiki ;; Author: Takeshi Arabiki -;; Version: 0.1.7 +;; Version: 0.2.0 ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ "Run Node.js REPL and communicate the process." :group 'processes) -(defconst nodejs-repl-version "0.1.7" +(defconst nodejs-repl-version "0.2.0" "Node.js mode Version.") (defcustom nodejs-repl-command "node" From 78f98c5dace317030a15f839d39fc15934e5bba8 Mon Sep 17 00:00:00 2001 From: abicky Date: Tue, 18 Sep 2018 02:00:29 +0900 Subject: [PATCH 9/9] Improve README --- README.md | 52 +++++++++++++++++++++++++++++--------------------- nodejs-repl.el | 20 +++++++++++++++++++ 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8ce4f42..626777d 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,10 @@ Description This program is derived from comint-mode and provides the following features. - * token completion, same as Node.js REPL - * file name completion in string - * incremental history search - * sending JavaScript codes to REPL +* token completion, same as Node.js REPL +* file name completion in string +* incremental history search +* sending JavaScript codes to REPL Usage ----- @@ -19,20 +19,24 @@ Usage Put this file in your Emacs lisp path (e.g. ~/.emacs.d/site-lisp) and add the following line to your .emacs: - (require 'nodejs-repl) +```elisp +(require 'nodejs-repl) +``` Type `M-x nodejs-repl` to run Node.js REPL. See also `comint-mode` to check key bindings. You can define key bindings to send JavaScript codes to REPL like below: - (add-hook 'js-mode-hook - (lambda () - (define-key js-mode-map (kbd "C-x C-e") 'nodejs-repl-send-last-expression) - (define-key js-mode-map (kbd "C-c C-j") 'nodejs-repl-send-line) - (define-key js-mode-map (kbd "C-c C-r") 'nodejs-repl-send-region) - (define-key js-mode-map (kbd "C-c C-l") 'nodejs-repl-load-file) - (define-key js-mode-map (kbd "C-c C-z") 'nodejs-repl-switch-to-repl))) +```elisp +(add-hook 'js-mode-hook + (lambda () + (define-key js-mode-map (kbd "C-x C-e") 'nodejs-repl-send-last-expression) + (define-key js-mode-map (kbd "C-c C-j") 'nodejs-repl-send-line) + (define-key js-mode-map (kbd "C-c C-r") 'nodejs-repl-send-region) + (define-key js-mode-map (kbd "C-c C-l") 'nodejs-repl-load-file) + (define-key js-mode-map (kbd "C-c C-z") 'nodejs-repl-switch-to-repl))) +``` When a version manager such as nvm is used to run different versions of Node.js, it is often desirable to start the REPL of the version @@ -40,19 +44,23 @@ specified in the .nvmrc file per project. In such case, customize the `nodejs-repl-command` variable with a function symbol. That function should query nvm for the Node.js command to run. For example: - (require 'nodejs-repl) - (defun nvm-which () - (let* ((shell (concat (getenv "SHELL") " -l -c 'nvm which'")) - (output (shell-command-to-string shell))) - (cadr (split-string output "[\n]+" t)))) - (setq nodejs-repl-command #'nvm-which) +```elisp +(require 'nodejs-repl) +(defun nvm-which () + (let* ((shell (concat (getenv "SHELL") " -l -c 'nvm which'")) + (output (shell-command-to-string shell))) + (cadr (split-string output "[\n]+" t)))) +(setq nodejs-repl-command #'nvm-which) +``` The `nvm-which` function can be simpler, and perhaps can run faster, too, if using Bash: - (defun nvm-which () - (let ((output (shell-command-to-string "source ~/.nvm/nvm.sh; nvm which"))) - (cadr (split-string output "[\n]+" t)))) +```elisp +(defun nvm-which () + (let ((output (shell-command-to-string "source ~/.nvm/nvm.sh; nvm which"))) + (cadr (split-string output "[\n]+" t)))) +``` Author ------ @@ -63,7 +71,7 @@ Takeshi Arabiki (abicky) Copyright and License --------------------- -Copyright (C) 2012-2017 Takeshi Arabiki (abicky) +Copyright (C) 2012-2018 Takeshi Arabiki (abicky) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/nodejs-repl.el b/nodejs-repl.el index 9a16def..f7bac73 100644 --- a/nodejs-repl.el +++ b/nodejs-repl.el @@ -44,6 +44,26 @@ ;; (define-key js-mode-map (kbd "C-c C-l") 'nodejs-repl-load-file) ;; (define-key js-mode-map (kbd "C-c C-z") 'nodejs-repl-switch-to-repl))) ;; +;; When a version manager such as nvm is used to run different versions +;; of Node.js, it is often desirable to start the REPL of the version +;; specified in the .nvmrc file per project. In such case, customize the +;; `nodejs-repl-command` variable with a function symbol. That function +;; should query nvm for the Node.js command to run. For example: +;; +;; (require 'nodejs-repl) +;; (defun nvm-which () +;; (let* ((shell (concat (getenv "SHELL") " -l -c 'nvm which'")) +;; (output (shell-command-to-string shell))) +;; (cadr (split-string output "[\n]+" t)))) +;; (setq nodejs-repl-command #'nvm-which) +;; +;; The `nvm-which` function can be simpler, and perhaps can run faster, +;; too, if using Bash: +;; +;; (defun nvm-which () +;; (let ((output (shell-command-to-string "source ~/.nvm/nvm.sh; nvm which"))) +;; (cadr (split-string output "[\n]+" t)))) +;; (require 'cc-mode) (require 'comint)