my-emacs-d/elpa/company-restclient-20151202.../company-restclient.el

141 lines
5.1 KiB
EmacsLisp

;;; company-restclient.el --- company-mode completion back-end for restclient-mode
;; Public domain.
;; Author: Iku Iwasa <iku.iwasa@gmail.com>
;; URL: https://github.com/iquiw/company-restclient
;; Package-Version: 20151202.401
;; Version: 0.2.0
;; Package-Requires: ((cl-lib "0.5") (company "0.8.0") (emacs "24") (know-your-http-well "0.2.0") (restclient "0.0.0"))
;;; Commentary:
;; `company-mode' back-end for `restclient-mode'.
;;
;; It provides auto-completion for HTTP methods and headers in `restclient-mode'.
;; Completion source is given by `know-your-http-well'.
;;; Code:
(require 'cl-lib)
(require 'company)
(require 'know-your-http-well)
(require 'restclient)
(defcustom company-restclient-header-values
'(("content-type" . ("application/json"
"application/xml"
"application/x-www-form-urlencoded"
"text/csv"
"text/html"
"text/plain")))
"Association list of completion candidates for HTTP header values.
The key is header name and the value is list of header values.")
(defvar company-restclient--current-context nil)
(defun company-restclient--find-context ()
"Find context (method, header, body) of the current line."
(save-excursion
(forward-line 0)
(cond
((looking-at-p "^:") 'vardecl)
((looking-at-p "^#") 'comment)
(t
(catch 'result
(let ((state 0))
(while (and (>= (forward-line -1) 0)
(null (looking-at-p "^#")))
(cond
((looking-at-p "^\\([[:space:]]*$\\|:\\)")
(cond
((= state 0) (setq state 1))
((= state 2) (setq state 3))))
((= state 0) (setq state 2))
((or (= state 1) (= state 3))
(throw 'result 'body))))
(if (or (= state 0) (= state 1))
(throw 'result 'method)
(throw 'result 'header))))))))
(defun company-restclient-prefix ()
"Provide completion prefix at the current point."
(cl-case (company-restclient--find-context)
(method (or (let ((case-fold-search nil)) (company-grab "^[[:upper:]]*"))
(company-restclient--grab-var)))
(header (or (company-grab "^[-[:alpha:]]*")
(company-restclient--grab-var)
(company-grab-symbol)))
(vardecl nil)
(comment nil)
(t (company-restclient--grab-var))))
(defun company-restclient--grab-var ()
"Grab variable for completion prefix."
(company-grab ".\\(:[^: \n]*\\)" 1))
(defun company-restclient-candidates (prefix)
"Provide completion candidates for the given PREFIX."
(cond
((string-match-p "^:" prefix)
(setq company-restclient--current-context 'varref)
(all-completions
prefix
(sort (mapcar #'car (restclient-find-vars-before-point)) #'string<)))
(t
(cl-case (setq company-restclient--current-context
(company-restclient--find-context))
(method
(all-completions prefix http-methods))
(header
(cond
((looking-back "^\\([-[:alpha:]]+\\): .*")
(setq company-restclient--current-context 'header-value)
(all-completions prefix
(cdr
(assoc
(downcase (match-string-no-properties 1))
company-restclient-header-values))))
(t
(all-completions (downcase prefix) http-headers))))))))
(defun company-restclient-meta (candidate)
"Return description of CANDIDATE to display as meta information."
(cl-case company-restclient--current-context
(method (cl-caadr (assoc candidate http-methods)))
(header (cl-caadr (assoc candidate http-headers)))))
(defun company-restclient-post-completion (candidate)
"Format CANDIDATE in the buffer according to the current context.
For HTTP method, insert space after it.
For HTTP header, capitalize if necessary and insert colon and space after it."
(cl-case company-restclient--current-context
(method (insert " "))
(header (let (start (end (point)))
(when (save-excursion
(backward-char (length candidate))
(setq start (point))
(let ((case-fold-search nil))
(looking-at-p "[[:upper:]]")))
(delete-region start end)
(insert
(mapconcat 'capitalize (split-string candidate "-") "-"))))
(insert ": "))))
;;;###autoload
(defun company-restclient (command &optional arg &rest ignored)
"`company-mode' completion back-end for `restclient-mode'.
Provide completion info according to COMMAND and ARG. IGNORED, not used."
(interactive (list 'interactive))
(cl-case command
(interactive (company-begin-backend 'company-restclient))
(prefix (and (derived-mode-p 'restclient-mode) (company-restclient-prefix)))
(candidates (company-restclient-candidates arg))
(ignore-case 'keep-prefix)
(meta (company-restclient-meta arg))
(post-completion (company-restclient-post-completion arg))))
(provide 'company-restclient)
;;; company-restclient.el ends here