diff options
Diffstat (limited to 'elpa/ac-js2-20190101.933/ac-js2.el')
-rw-r--r-- | elpa/ac-js2-20190101.933/ac-js2.el | 608 |
1 files changed, 0 insertions, 608 deletions
diff --git a/elpa/ac-js2-20190101.933/ac-js2.el b/elpa/ac-js2-20190101.933/ac-js2.el deleted file mode 100644 index 1951388..0000000 --- a/elpa/ac-js2-20190101.933/ac-js2.el +++ /dev/null @@ -1,608 +0,0 @@ -;;; ac-js2.el --- Auto-complete source for Js2-mode, with navigation - -;; Copyright (C) 2013 Scott Barnett - -;; Author: Scott Barnett <scott.n.barnett@gmail.com> -;; URL: https://github.com/ScottyB/ac-js2 -;; Version: 1.0 -;; Package-Requires: ((js2-mode "20090723")(skewer-mode "1.4")) - -;; 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 -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. - -;;; Commentary: - -;; An attempt to get context sensitive Javascript completion in Emacs. -;; Basic completions are obtained by parsing Javascript code with -;; Js2-mode's parser. -;; -;; Installation -;; -;; Easiest way to get ac-js2 is to install it from MELPA. You may need -;; this snippet -;; -;; `(add-to-list 'package-archives -;; '("melpa" . "http://melpa.milkbox.net/packages/") t)' -;; -;; if you don't have it already to fetch packages from MELPA. -;; -;; Enable ac-js2 in js2-mode as follows: -;; -;; (add-hook 'js2-mode-hook 'ac-js2-mode) -;; -;; Ac-js2 does not require auto-complete mode but I suggest you grab -;; it anyway as ac-js2 is designed to work with a completion frontend. -;; Support for Company mode is on its way. -;; -;; For more comprehensive completions you can opt to evaluate the code -;; for candidates. A browser needs to be connected to Emacs for the -;; evaluation completions to work. Put this in your init.el file. -;; -;; `(setq ac-js2-evaluate-calls t)' -;; -;; To add completions for external libraries add something like this: -;; -;; (add-to-list 'ac-js2-external-libraries "path/to/lib/library.js") -;; -;; Then connect a browser to Emacs by calling `(run-skewer)'. You may -;; need to save the buffer for completions to start. -;; -;; If auto-complete mode is installed on your system then completions -;; should start showing up otherwise use `completion-at-point'. -;; -;; Note: library completions will only work if `ac-js2-evaluate-calls' -;; is set and a browser is connected to Emacs. -;; -;; Bonus: M-. is bound to `ac-js2-jump-to-definition' which will jump -;; to Javascript definitions found in the same buffer. Given the -;; following proprety reference: -;; -;; foo.bar.baz(); -;; -;; placing the cursor on `foo', `bar' or `baz' and executing M-. will -;; take you straight to their respective definitions. Use M-, to jump -;; back to where you were. Also works for object literals. -;; -;; Recently added `ac-js2-expand-function' that will expand a function's -;; parameters bound to `C-c C-c`. Expansion will only work if the cursor -;; is after the function. -;; -;; If you have any issues or suggestions please create an issue on Github: -;; https://github.com/ScottyB/ac-js2 - -;;; History: - -;; Version 1.0 -;; * Navigation within current buffer -;; * Completion and docstring for objects via Skewer -;; * External library support -;; * Basic completions of objects in current buffer - -;;; Code: - -(require 'js2-mode) -(require 'skewer-mode) -(require 'cl-lib) -(require 'etags) - -(defgroup ac-js2 nil - "Auto-completion for js2-mode." - :group 'completion - :prefix "ac-js2-") - -;;; Configuration variables - -(defcustom ac-js2-add-ecma-262-externs t - "If non-nil add `js2-ecma-262-externs' to completion candidates.") - -(defcustom ac-js2-add-browser-externs t - "If non-nil add `js2-browser-externs' to completion candidates.") - -(defcustom ac-js2-add-keywords t - "If non-nil add `js2-keywords' to completion candidates.") - -(defcustom ac-js2-add-prototype-completions t - "When non-nil traverse the prototype chain adding to completion candidates.") - -(defcustom ac-js2-external-libraries '() - "List of absolute paths to external Javascript libraries.") - -(defcustom ac-js2-evaluate-calls nil - "Warning. When true function calls will be evaluated in the browser. -This may cause undesired side effects however it will - provide better completions. Use at your own risk.") - -(defcustom ac-js2-force-reparse t - "Force Js2-mode to reparse buffer before fetching completion candidates.") - -;;; Internal variables - -(defvar ac-js2-keywords '() - "Cached string version of `js2-keywords'.") - -(defvar ac-js2-candidates '()) - -;; Types of skewer completion methods available -(defconst ac-js2-method-eval 0) -(defconst ac-js2-method-global 1 - "Return candidates for the global object. -Only keys of the object are returned as the other properties come - from js2-mode's externs.") - -(defvar ac-js2-data-root (file-name-directory load-file-name) - "Location of data files needed for `ac-js2-on-skewer-load'.") - -;;; Skewer integration - -(defvar ac-js2-skewer-candidates '() - "Cadidates obtained from skewering.") - -(defun ac-js2-on-skewer-load () - "Inject skewer addon and evaluate external libraries in browser." - (insert-file-contents (expand-file-name "skewer-addon.js" ac-js2-data-root)) - (and ac-js2-evaluate-calls - (mapcar (lambda (library) - (with-temp-buffer - (insert-file-contents (expand-file-name library)) - (skewer-eval (buffer-string) - nil - :type "complete"))) ac-js2-external-libraries))) - -(defun ac-js2-skewer-completion-candidates () - "Get completions returned from skewer." - (mapcar (lambda (candidate) (symbol-name (car candidate))) ac-js2-skewer-candidates)) - -(defun ac-js2-skewer-document-candidates (name) - "Return document string for NAME from skewer." - (let ((doc (cdr (assoc-string name ac-js2-skewer-candidates)))) - (or (ac-js2-format-function doc) doc))) - -(defun ac-js2-get-object-properties (name) - "Find properties of NAME for completion." - (ac-js2-skewer-eval-wrapper name `((prototypes . ,ac-js2-add-prototype-completions)))) - -(defun ac-js2-skewer-result-callback (result) - "Process the RESULT passed from the browser." - (let ((value (cdr (assoc 'value result)))) - (if (and (skewer-success-p result) value) - (setq ac-js2-skewer-candidates (append value nil))))) - -(defun ac-js2-skewer-eval-wrapper (str &optional extras) - "Wrap `skewer-eval-synchronously' to check if a skewer-client is avilable. -STR is the text to send to the browser for evaluation. Extra -parameters can be passed to the browser using EXTRAS. EXTRAS must -be of the form (param-string . value) where param-string is the -reference and value is the value that can be retrieved from the -request object in Javacript." - (setq ac-js2-skewer-candidates nil) - (if skewer-clients - (if (or ac-js2-evaluate-calls - (not (ac-js2-has-function-calls str))) - (ac-js2-skewer-result-callback - (skewer-eval-synchronously str - :type "complete" - :extra extras))) - (setq skewer-queue nil))) - -;; Generate candidates -(defun ac-js2-candidates () - "Main function called to gather candidates for auto-completion." - (if ac-js2-force-reparse (js2-reparse)) - (let ((node (js2-node-parent (js2-node-at-point (1- (point))))) - beg - (prop-get-regex "[a-zA-Z)]\\.") - name) - (setq ac-js2-candidates nil) - (cond - ((looking-back "\\.") - ;; TODO: Need to come up with a better way to extract object than this regex!! - (save-excursion - (setq beg (and (skip-chars-backward "[a-zA-Z_$][0-9a-zA-Z_$#\"())]+\\.") (point)))) - (setq name (buffer-substring-no-properties beg (1- (point)))) - (ac-js2-get-object-properties name) - (setq node (ac-js2-initialized-node (if (string-match prop-get-regex name) - (reverse (split-string name prop-get-regex)) name))) - (if (js2-object-node-p node) - (setq ac-js2-candidates - (mapcar (lambda (elem) - (ac-js2-format-node (js2-node-string (js2-object-prop-node-left elem)) - elem)) - (js2-object-node-elems node)))) - (append (mapcar 'cl-first ac-js2-candidates) - (ac-js2-skewer-completion-candidates))) - ((js2-prop-get-node-p node) - (setq node (js2-prop-get-node-left node)) - (setq name (js2-node-string node)) - (ac-js2-get-object-properties name) - (ac-js2-skewer-completion-candidates)) - (t - (ac-js2-skewer-eval-wrapper "" `((method . ,ac-js2-method-global))) - (append (ac-js2-skewer-completion-candidates) - (ac-js2-add-extra-completions - (mapcar 'cl-first (ac-js2-get-names-in-scope)))))))) - -(defun ac-js2-document (name) - "Show documentation for NAME from local buffer if present -otherwise use documentation obtained from skewer." - (let* ((docs (cdr (assoc name ac-js2-candidates))) - (doc (if (listp docs) (cl-first docs) docs))) - (if doc doc (ac-js2-skewer-document-candidates name)))) - -;; Auto-complete settings - -(defun ac-js2-ac-candidates () - "Completion candidates for auto-complete mode." - (ac-js2-candidates)) - -(defun ac-js2-ac-document (name) - "Documentation to be shown for auto-complete mode." - (ac-js2-document name)) - -(defun ac-js2-ac-prefix() - (or (ac-prefix-default) (ac-prefix-c-dot))) - -(defun ac-js2-save () - "Called on `before-save-hook' to evaluate buffer." - (interactive) - (when (string= major-mode "js2-mode") - (ac-js2-skewer-eval-wrapper (buffer-string))) - t) - -;;;###autoload -(defun ac-js2-expand-function() - "Expand the function definition left of point. -Expansion will only occur for candidates whose documentation -string contain a function prototype." - (interactive) - (let* ((word (progn - (if (featurep 'auto-complete) (ac-complete)) - (substring-no-properties (or (thing-at-point 'word) "")))) - (candidate (ac-js2-ac-document word))) - (if (and (looking-back word) (stringp candidate)) - (when (string-match "^function" candidate) - (cond ((featurep 'yasnippet) - (yas-expand-snippet - (concat "(" - (replace-regexp-in-string "\\([a-zA-Z0-9]+\\)" - (lambda (txt) (concat "${" txt "}")) - (cl-second (split-string candidate "[()]"))) - ")$0")))))))) - -(defun ac-js2-setup-auto-complete-mode () - "Setup ac-js2 to be used with auto-complete-mode." - (add-to-list 'ac-sources 'ac-source-js2) - (auto-complete-mode) - (ac-define-source "js2" - '((candidates . ac-js2-ac-candidates) - (document . ac-js2-ac-document) - (prefix . ac-js2-ac-prefix) - (requires . -1)))) - -;;; Completion at point function - -;;;###autoload -(defun ac-js2-completion-function () - "Function for `completions-at-point'." - (save-excursion - (let ((bounds (if (looking-back "\\.") - (cons (point) (point)) - (bounds-of-thing-at-point 'word)))) - (list (car bounds) (cdr bounds) (ac-js2-candidates))))) - -;;; Company - -;;;###autoload -(defun ac-js2-company (command &optional arg &rest ignored) - (interactive (list 'interactive)) - (if (not (featurep 'company)) - (message "Company is not installed") - (cl-case command - (interactive (company-begin-backend 'ac-js2-company)) - (prefix (when ac-js2-mode - (or (company-grab-symbol) - 'stop))) - (candidates (all-completions arg (ac-js2-candidates))) - (duplicates t) - (meta (let ((doc (ac-js2-document arg))) - (when doc - (with-temp-buffer - (insert doc) - (js-mode) - (if (fboundp 'font-lock-ensure) - (font-lock-ensure) - (with-no-warnings - (font-lock-fontify-buffer))) - (buffer-string)))))))) - -;;; Helper functions - -(defun ac-js2-build-prop-name-list (prop-node) - "Build a list of names from a PROP-NODE." - (let* (names - left - left-node) - (unless (js2-prop-get-node-p prop-node) - (error "Node is not a property prop-node")) - (while (js2-prop-get-node-p prop-node) - (push (js2-name-node-name (js2-prop-get-node-right prop-node)) names) - (setq left-node (js2-prop-get-node-left prop-node)) - (when (js2-name-node-p left-node) - (setq left (js2-name-node-name left-node))) - (setq prop-node (js2-node-parent prop-node))) - (append names `(,left)))) - -(defun ac-js2-prop-names-left (name-node) - "Create a list of all of the names in the property NAME-NODE. -NAME-NODE must have a js2-prop-get-node as parent. Only adds -properties to the left of point. This is so individual jump -points can be found for each property in the chain." - (let* (name - (parent (js2-node-parent name-node)) - left - names) - (unless (or (js2-prop-get-node-p parent) (js2-name-node-p name-node)) - (error "Not a name node or doesn't have a prop-get-node as parent")) - (setq name (js2-name-node-name name-node) - left (js2-prop-get-node-left parent)) - (if (and (js2-name-node-p left) - (string= name (js2-name-node-name left))) - (setq names name) - (js2-visit-ast - parent - (lambda (node endp) - (unless endp - (if (js2-name-node-p node) - (push (js2-name-node-name node) names) - t)))) - names))) - -(defun ac-js2-has-function-calls (string) - "Check if the Javascript code in STRING has a Js2-call-node." - (with-temp-buffer - (insert string) - (let* ((ast (js2-parse))) - (catch 'call-node - (js2-visit-ast-root - ast - (lambda (node end-p) - (unless end-p - (if (js2-call-node-p node) - (throw 'call-node t) - t)))))))) - -(defun ac-js2-add-extra-completions (completions) - "Add extra candidates to COMPLETIONS." - (append completions - (if ac-js2-add-keywords (or ac-js2-keywords (setq ac-js2-keywords (mapcar 'symbol-name js2-keywords)))) - (if ac-js2-add-ecma-262-externs js2-ecma-262-externs) - (if ac-js2-add-browser-externs js2-browser-externs))) - -(defun ac-js2-root-or-node () - "Return the current node or js2-ast-root node." - (let ((node (js2-node-at-point))) - (if (js2-ast-root-p node) - node - (js2-node-get-enclosing-scope node)))) - -(defun ac-js2-get-names-in-scope () - "Fetches all symbols in scope and formats them for completion." - (let* ((scope (ac-js2-root-or-node)) - result) - (while scope - (setq result (append result - (cl-loop for item in (js2-scope-symbol-table scope) - if (not (assoc (car item) result)) - collect item))) - (setq scope (js2-scope-parent-scope scope))) - (setq ac-js2-candidates - (mapcar #'(lambda (x) - (let* ((name (symbol-name (car x))) - (init (ac-js2-initialized-node name))) - (ac-js2-format-node name init))) - result)))) - -(defun ac-js2-initialized-node (name) - "Return initial value assigned to NAME. -NAME may be either a variable, a function or a variable that -holds a function. NAME may also be a list of names that make up a -object property. Returns nil if no initial value can be found." - (let* ((node (if (listp name) (ac-js2-find-property name) - (ac-js2-name-declaration name))) - (parent (if node (js2-node-parent node))) - (init (cond - ((js2-function-node-p parent) - parent) - ((js2-function-node-p node) - node) - ((js2-var-init-node-p parent) - (js2-var-init-node-initializer parent)) - ((js2-assign-node-p parent) - (js2-assign-node-right parent)) - (t - nil)))) - init)) - -(defun ac-js2-name-declaration (name) - "Return the declaration node for node named NAME." - (let* ((node (ac-js2-root-or-node)) - (scope-def (js2-get-defining-scope node name)) - (scope (if scope-def (js2-scope-get-symbol scope-def name) nil)) - (symbol (if scope (js2-symbol-ast-node scope) nil))) - (if (not symbol) - (ac-js2-get-function-node name scope-def) - symbol))) - -;;; Completion candidate formatting - -(defun ac-js2-format-node (name node) - "Format NAME and NODE for completion. -Returned format is a list where the first element is the NAME of -the node (shown in completion candidate list) and the last -element is the text to show as documentation." - (let ((node (if (js2-object-prop-node-p node) (js2-object-prop-node-right node) node)) - (name-format (replace-regexp-in-string "\"" "" name)) - (doc (if (and (js2-function-node-p node) - (cl-find name (js2-function-node-params node) - :test '(lambda (name param) (string= name (js2-name-node-name param))))) - "Function parameter" - (ac-js2-format-node-doc node)))) - `(,name-format . ,doc))) - -(defun ac-js2-format-object-node-doc (obj-node) - "Format OBJ-NODE to display as documentation." - (let (elems) - (unless (js2-object-node-p obj-node) - (error "Node is not an object node")) - (setq elems (js2-object-node-elems obj-node)) - (if (not elems) - "{}" - (mapconcat #'(lambda (x) (ac-js2-format-js2-object-prop-doc x)) elems "\n")))) - -(defun ac-js2-format-node-doc (node) - "Format NODE for displaying in a document string." - (let* ((node-above (and node (js2-node-at-point - (save-excursion - (goto-char (js2-node-abs-pos node)) - (forward-line -1) - (point))))) - (comment (if (js2-comment-node-p node-above) - (ac-js2-format-comment (js2-node-string node-above)))) - (doc (cond - ((js2-function-node-p node) - (ac-js2-format-function node)) - ((js2-object-node-p node) - (ac-js2-format-object-node-doc node)) - ((js2-object-prop-node-p node) - (ac-js2-format-node-doc (js2-object-prop-node-right node))) - (t - (if (js2-node-p node) (js2-node-string node) ""))))) - (if comment (concat comment "\n" doc) doc))) - -(defun ac-js2-format-js2-object-prop-doc (obj-prop) - "Format an OBJ-PROP for displaying as a document string." - (unless (js2-object-prop-node-p obj-prop) - (error "Node is not an object property node")) - (let* ((left (js2-object-prop-node-left obj-prop)) - (right (js2-object-prop-node-right obj-prop))) - (concat (js2-node-string left) " : " - (ac-js2-format-node-doc right)))) - -(defun ac-js2-format-function (func) - "Formats a function for a document string. -FUNC can be either a function node or a string starting with -'function'. Returns nil if neither." - (let ((str (or (and (js2-function-node-p func) (js2-node-string func)) - (and (stringp func) (eq 0 (string-match "function" func)) func)))) - (if str (substring str 0 (1+ (string-match ")" str)))))) - -(defun ac-js2-format-comment (comment) - "Prepare a COMMENT node for displaying in a popup." - (let* ((node-string (if (js2-comment-node-p comment) - (js2-node-string comment) - comment)) - (string (replace-regexp-in-string "[ \t]$" "" - (replace-regexp-in-string "^[ \t\n*/*]+" "" node-string)))) - string)) - -;;; Navigation commands for js2-mode - -(defun ac-js2-find-property (list-names) - "Find the property definition that consists of LIST-NAMES. -Supports navigation to 'foo.bar = 3' and 'foo = {bar: 3}'." - (catch 'prop-found - (js2-visit-ast-root - js2-mode-ast - (lambda (node endp) - (let ((parent (js2-node-parent node))) - (unless endp - (if (or (and (js2-prop-get-node-p node) - (not (or (js2-elem-get-node-p parent) (js2-call-node-p parent))) - (equal list-names (ac-js2-build-prop-name-list node))) - (and (js2-name-node-p node) - (js2-object-prop-node-p parent) - (string= (js2-name-node-name node) - (cl-first list-names)))) - (throw 'prop-found node)) - t)))))) - -(defun ac-js2-get-function-node (name scope) - "Return node of function named NAME in SCOPE." - (catch 'function-found - (js2-visit-ast - scope - (lambda (node end-p) - (when (and (not end-p) - (string= name (ac-js2-get-function-name node))) - (throw 'function-found node)) - t)) - nil)) - -;;;###autoload -(defun ac-js2-jump-to-definition () - "Jump to the definition of an object's property, variable or function. -Navigation to a property definend in an Object literal isn't -implemented." - (interactive) - (ring-insert find-tag-marker-ring (point-marker)) - (let* ((node (js2-node-at-point)) - (parent (js2-node-parent node)) - (prop-names (if (js2-prop-get-node-p parent) - (ac-js2-prop-names-left node))) - (name (if (and (js2-name-node-p node) - (not (js2-object-prop-node-p parent))) - (js2-name-node-name node) - (error "Node is not a supported jump node"))) - (node-init (if (and prop-names (listp prop-names)) - (ac-js2-find-property prop-names) - (ac-js2-name-declaration name)))) - (unless node-init - (pop-tag-mark) - (error "No jump location found")) - (goto-char (js2-node-abs-pos node-init)))) - -(defun ac-js2-get-function-name (fn-node) - "Return the name of the function FN-NODE. -Value may be either function name or the variable name that holds -the function." - (let ((parent (js2-node-parent fn-node))) - (if (js2-function-node-p fn-node) - (or (js2-function-name fn-node) - (if (js2-var-init-node-p parent) - (js2-name-node-name (js2-var-init-node-target parent))))))) - -(defvar ac-js2-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "M-.") 'ac-js2-jump-to-definition) - (define-key map (kbd "M-,") 'pop-tag-mark) - (define-key map (kbd "C-c C-c") 'ac-js2-expand-function) - map) - "Keymap for `ac-js2-mode'.") - -;;; Minor mode - -;;;###autoload -(define-minor-mode ac-js2-mode - "A minor mode that provides auto-completion and navigation for Js2-mode." - :keymap ac-js2-mode-map - (if (featurep 'auto-complete) - (ac-js2-setup-auto-complete-mode)) - (set (make-local-variable 'completion-at-point-functions) - (cons 'ac-js2-completion-function completion-at-point-functions)) - (ac-js2-skewer-eval-wrapper (buffer-string)) - (add-hook 'before-save-hook 'ac-js2-save nil t) - (add-hook 'skewer-js-hook 'ac-js2-on-skewer-load)) - - -(provide 'ac-js2) - -;;; ac-js2.el ends here |