-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcompany-restclient.el
139 lines (122 loc) · 5.15 KB
/
company-restclient.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
;;; company-restclient.el --- company-mode completion back-end for restclient-mode -*- lexical-binding: t -*-
;; Public domain.
;; Author: Iku Iwasa <[email protected]>
;; URL: https://github.com/iquiw/company-restclient
;; Version: 0.3.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)))
(comment nil)
;; Try to grab variable for vardecl too, as it can be variable reference.
(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