diff options
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/company-flow-20180225.1359/company-flow.el')
-rw-r--r-- | configs/shared/emacs/.emacs.d/elpa/company-flow-20180225.1359/company-flow.el | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/company-flow-20180225.1359/company-flow.el b/configs/shared/emacs/.emacs.d/elpa/company-flow-20180225.1359/company-flow.el new file mode 100644 index 000000000000..28332c394a83 --- /dev/null +++ b/configs/shared/emacs/.emacs.d/elpa/company-flow-20180225.1359/company-flow.el @@ -0,0 +1,209 @@ +;;; company-flow.el --- Flow backend for company-mode -*- lexical-binding: t -*- + +;; Copyright (C) 2016 by Aaron Jensen + +;; Author: Aaron Jensen <aaronjensen@gmail.com> +;; URL: https://github.com/aaronjensen/company-flow +;; Package-Version: 20180225.1359 +;; Version: 0.1.0 +;; Package-Requires: ((company "0.8.0") (dash "2.13.0")) + +;;; Commentary: + +;; This package adds support for flow to company. It requires +;; flow to be in your path. + +;; To use it, add to your company-backends: + +;; (eval-after-load 'company +;; '(add-to-list 'company-backends 'company-flow)) + +;;; License: + +;; This file is not part of GNU Emacs. +;; However, it is distributed under the same license. + +;; GNU Emacs 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, or (at your option) +;; any later version. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Code: +(require 'company) +(require 'dash) + +(defgroup company-flow () + "Flow company backend." + :group 'company + :prefix "company-flow-") + +(defcustom company-flow-executable "flow" + "Flow executable to run." + :group 'company-flow + :type 'string) +(make-variable-buffer-local 'company-flow-executable) + +(defcustom company-flow-modes '( + js-mode + js-jsx-mode + js2-mode + js2-jsx-mode + rjsx-mode + web-mode + ) + "List of major modes where company-flow will be providing completions." + :type '(choice (const :tag "All" nil) + (repeat (symbol :tag "Major mode"))) + :group 'company-flow) + +(defun company-flow--handle-signal (process _event) + (when (memq (process-status process) '(signal exit)) + (let ((callback (process-get process 'company-flow-callback)) + (prefix (process-get process 'company-flow-prefix))) + (if (and (eq (process-status process) 'exit) + (eq (process-exit-status process) 0)) + (funcall callback (->> process + company-flow--get-output + company-flow--parse-output + ;; Remove nils + (--filter it))) + (funcall callback nil))))) + +(defun company-flow--make-candidate (line) + "Creates a candidate with a meta property from LINE. + +LINE is expected to look like: +registrationSuccess () => {type: 'REGISTRATION_SUCCESS'}" + (let ((first-space (string-match " " line))) + (when first-space + (let ((text (substring line 0 first-space)) + (meta (substring line (+ 1 first-space)))) + (propertize text 'meta meta))))) + +(defun company-flow--parse-output (output) + (when (not (equal output "Error: not enough type information to autocomplete\n")) + (mapcar 'company-flow--make-candidate + (split-string output "\n")))) + +(defun company-flow--get-output (process) + "Get the complete output of PROCESS." + (with-demoted-errors "Error while retrieving process output: %S" + (let ((pending-output (process-get process 'company-flow-pending-output))) + (apply #'concat (nreverse pending-output))))) + +(defun company-flow--receive-checker-output (process output) + "Receive a syntax checking PROCESS OUTPUT." + (push output (process-get process 'company-flow-pending-output))) + +(defun company-flow--process-send-buffer (process) + "Send all contents of current buffer to PROCESS. + +Sends all contents of the current buffer to the standard input of +PROCESS, and terminates standard input with EOF." + (save-restriction + (widen) + (process-send-region process (point-min) (point-max))) + ;; flow requires EOF be on its own line + (process-send-string process "\n") + (process-send-eof process)) + +(defun company-flow--candidates-query (prefix callback) + (let* ((line (line-number-at-pos (point))) + (col (+ 1 (current-column))) + (command (list (executable-find company-flow-executable) + "autocomplete" + "--quiet" + buffer-file-name + (number-to-string line) + (number-to-string col))) + (process-connection-type nil) + (process (apply 'start-process "company-flow" nil command))) + (set-process-sentinel process #'company-flow--handle-signal) + (set-process-filter process #'company-flow--receive-checker-output) + (process-put process 'company-flow-callback callback) + (process-put process 'company-flow-prefix prefix) + (company-flow--process-send-buffer process))) + +(defun company-flow--prefix () + "Grab prefix for flow." + (and (or (null company-flow-modes) + (-contains? company-flow-modes major-mode)) + company-flow-executable + (executable-find company-flow-executable) + buffer-file-name + (file-exists-p buffer-file-name) + (not (company-in-string-or-comment)) + (locate-dominating-file buffer-file-name ".flowconfig") + (or (company-grab-symbol-cons "\\." 1) + 'stop))) + +(defun company-flow--annotation (candidate) + (format " %s" (get-text-property 0 'meta candidate))) + +(defun company-flow--meta (candidate) + (format "%s: %s" candidate (get-text-property 0 'meta candidate))) + +(defvar-local company-flow--debounce-state nil) + +(defun company-flow--debounce-callback (prefix callback) + (lambda (candidates) + (let ((current-prefix (car company-flow--debounce-state)) + (current-callback (cdr company-flow--debounce-state))) + (when (and current-prefix + (company-flow--string-prefix-p prefix current-prefix)) + (setq company-flow--debounce-state nil) + (funcall current-callback (all-completions current-prefix candidates)))))) + +(defun company-flow--prefix-to-string (prefix) + "Return a string or nil from a prefix. + `company-grab-symbol-cons' can return (\"prefix\" . t) or just + \"prefix\", but we only care about the string." + (if (consp prefix) + (car prefix) + prefix)) + +(defun company-flow--string-prefix-p (a b) + (string-prefix-p (company-flow--prefix-to-string a) (company-flow--prefix-to-string b))) + +(defun company-flow--debounce-async (prefix candidate-fn) + "Return a function that will properly debounce candidate queries by comparing the +in-flight query's prefix to PREFIX. CANDIDATE-FN should take two arguments, PREFIX +and the typical async callback. + +Note that the candidate list provided to the callback by CANDIDATE-FN will be +filtered via `all-completions' with the most current prefix, so it is not necessary +to do this filtering in CANDIDATE-FN. + +Use like: + + (cons :async (company-flow--debounce-async arg 'your-query-fn))" + (lambda (callback) + (let ((current-prefix (car company-flow--debounce-state))) + (unless (and current-prefix + (company-flow--string-prefix-p prefix current-prefix)) + (funcall candidate-fn prefix (company-flow--debounce-callback prefix callback))) + (setq company-flow--debounce-state (cons (company-flow--prefix-to-string prefix) callback))))) + +;;;###autoload +(defun company-flow (command &optional arg &rest _args) + (interactive (list 'interactive)) + (pcase command + (`interactive (company-begin-backend 'company-flow)) + (`prefix (company-flow--prefix)) + (`annotation (company-flow--annotation arg)) + (`meta (company-flow--meta arg)) + (`sorted t) + (`candidates (cons :async (company-flow--debounce-async arg 'company-flow--candidates-query))))) + +(provide 'company-flow) +;;; company-flow.el ends here |