magnars-js2r-extract-function.md

(defun js2r--extract-fn (name goto-position call-template function-template)
  (js2r--guard)
  (js2r--wait-for-parse
   (unless (use-region-p)
     (error "Mark the expressions to extract first"))
   (save-excursion
     (let* ((parent (js2r--first-common-ancestor-in-region (region-beginning) (region-end)))
	    (block (js2r--closest-node-where #'js2-block-node-p parent))
	    (fn (js2r--closest-node-where #'js2-function-node-p block))
	    (exprs (js2r--marked-expressions-in-block block))
	    (vars (-mapcat #'js2r--name-node-decendants exprs))
	    (local (--filter (js2r--local-to-fn-p fn it) vars))
	    (names (-distinct (-map 'js2-name-node-name local)))
	    (declared-in-exprs (-map #'js2r--var-init-node-target-name (-mapcat #'js2r--var-init-node-decendants exprs)))
	    (outside-exprs (-difference (js2-block-node-kids block) exprs))
	    (outside-var-uses (-map #'js2-name-node-name (-mapcat #'js2r--name-node-decendants outside-exprs)))
	    (declared-in-but-used-outside (-intersection declared-in-exprs outside-var-uses))
	    (export-var (car declared-in-but-used-outside))
	    (params (-difference names declared-in-exprs))
	    (params-string (mapconcat #'identity (reverse params) ", "))
	    (first (car exprs))
	    (last (car (last exprs)))
	    (beg (js2-node-abs-pos (car exprs)))
	    (end (js2-node-abs-end last))
	    (contents (buffer-substring beg end)))
       (goto-char beg)
       (delete-region beg end)
       (when (js2-return-node-p last)
	 (insert "return "))
       (when export-var
	 (setq contents (concat contents "\nreturn " export-var ";"))
	 (insert "var " export-var " = "))
       (insert (format call-template name params-string))
       (goto-char (js2-node-abs-pos fn))
       (when goto-position (funcall goto-position))
       (let ((start (point)))
	 (insert (format function-template name params-string contents))
	 (indent-region start (1+ (point))))))))


(defun js2r-extract-function (name)
  "Extract a function from the closest statement expression from the point."
  (interactive "sName of new function: ")
  (js2r--extract-fn
   name
   (lambda ()
       (unless (js2r--looking-at-function-declaration)
         (goto-char (js2-node-abs-pos (js2r--closest #'js2-expr-stmt-node-p)))))
   "%s(%s);"
   "function %s(%s) {\n%s\n}\n\n"))Language:Clojure
(defun js2r--extract-fn (name goto-position call-template function-template)
  (js2r--guard)
  (js2r--wait-for-parse
   (unless (use-region-p)
     (error "Mark the expressions to extract first"))
   (save-excursion
     (let* ((parent (js2r--first-common-ancestor-in-region (region-beginning) (region-end)))
	    (block (js2r--closest-node-where #'js2-block-node-p parent))
	    (fn (js2r--closest-node-where #'js2-function-node-p block))
	    (exprs (js2r--marked-expressions-in-block block))
	    (vars (-mapcat #'js2r--name-node-decendants exprs))
	    (local (--filter (js2r--local-to-fn-p fn it) vars))
	    (names (-distinct (-map 'js2-name-node-name local)))
	    (declared-in-exprs (-map #'js2r--var-init-node-target-name (-mapcat #'js2r--var-init-node-decendants exprs)))
	    (outside-exprs (-difference (js2-block-node-kids block) exprs))
	    (outside-var-uses (-map #'js2-name-node-name (-mapcat #'js2r--name-node-decendants outside-exprs)))
	    (declared-in-but-used-outside (-intersection declared-in-exprs outside-var-uses))
	    (export-var (car declared-in-but-used-outside))
	    (params (-difference names declared-in-exprs))
	    (params-string (mapconcat #'identity (reverse params) ", "))
	    (first (car exprs))
	    (last (car (last exprs)))
	    (beg (js2-node-abs-pos (car exprs)))
	    (end (js2-node-abs-end last))
	    (contents (buffer-substring beg end)))
       (goto-char beg)
       (delete-region beg end)
       (when (js2-return-node-p last)
	 (insert "return "))
       (when export-var
	 (setq contents (concat contents "\nreturn " export-var ";"))
	 (insert "var " export-var " = "))
       (insert (format call-template name params-string))
       (goto-char (js2-node-abs-pos fn))
       (when goto-position (funcall goto-position))
       (let ((start (point)))
	 (insert (format function-template name params-string contents))
	 (indent-region start (1+ (point))))))))