-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanother-emacs-server.el
119 lines (104 loc) · 4.19 KB
/
another-emacs-server.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
;;; another-emacs-server.el --- An Emacs server built on HTTP and JSON -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Xu Chunyang
;; Author: Xu Chunyang
;; Homepage: https://github.com/xuchunyang/another-emacs-server
;; Package-Requires: ((emacs "25.1") (web-server "20200312"))
;; Keywords: processes
;; Version: 0
;; 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;; An Emacs Server built on HTTP and JSON
;;; Code:
(require 'web-server)
(require 'json)
(defgroup another-emacs-server nil
"An Emacs Server built on HTTP and JSON."
:group 'external)
(defcustom another-emacs-server-host "localhost"
"Host used by the another Emacs server."
:type 'string)
(defcustom another-emacs-server-port 7777
"Port used by the another Emacs server."
:type 'integer)
(defun another-emacs-server--response (process status object)
"Send JSON response to PROCESS.
STATUS is an HTTP status code.
OBJECT is an Emacs Lisp value, will be encoded in JSON, as response body."
(let ((json (condition-case err
(json-encode object)
(json-error
(json-encode
`((error . ,(concat "json-encode: " (error-message-string err)))))))))
(process-send-string
process
(concat
(format "HTTP/1.1 %d %s\r\n" status (alist-get status ws-status-codes))
"Content-Type: application/json\r\n"
(format "Content-Length: %d\r\n" (string-bytes json))
"\r\n"
json))))
;;;###autoload
(defun another-emacs-server ()
"Start the Emacs server."
(interactive)
(ws-start
(lambda (request)
(with-slots (process context) request
(let* ((err nil)
(body
(pcase context
('application/json
(condition-case err1
(let ((json-object-type 'alist)
(json-key-type 'symbol)
(json-array-type 'list)
(json-false nil)
(json-null nil))
(json-read-from-string
(substring
(oref request pending)
(oref request index))))
(json-error (setq err (error-message-string err1)))))
(_ (setq err "The request body is not in JSON")))))
(cond
(err
(another-emacs-server--response process 400 `((error . ,err))))
(t
(cond
((assq 'eval body)
(another-emacs-server--response
process
200
(condition-case err
`((result . ,(with-local-quit (eval (read (alist-get 'eval body)) t))))
(error
`((error . ,(error-message-string err)))))))
((assq 'file body)
(let ((files (alist-get 'file body)))
(cond
((stringp files) (setq files (list files)))
((listp files) (cl-loop for f in files
unless (stringp f)
do (setq err (format "%S is not a string" f))))
(t (setq err (format "%S is not a list of files" files))))
(unless err
(ignore-errors (mapc #'find-file files)))
(another-emacs-server--response
process
200
(cond (err `((error . ,err)))
(t `((result . ,"OK")))))))))))))
another-emacs-server-port
nil
:host another-emacs-server-host))
(provide 'another-emacs-server)
;;; another-emacs-server.el ends here