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
| | ;;; json-sexp-mode.el --- Edit JSON in s-expression form.
;; Copyright (C) 2015 Free Software Foundation, Inc.
;; Author: Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
;; Keywords: data, files
;; 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:
;; Activating `json-sexp-mode' will turn the JSON value in the buffer into an
;; s-expression, and arrange for it to be transparently converted back into a
;; (pretty-printed) JSON value whenever the buffer is saved. Adding
;; `json-sexp-mode' to `auto-mode-alist' can provide a fully transparent
;; experience for editing JSON files as s-expressions.
;;
;; The symbol `false' is used to represent JSON's false value, because nil
;; stands for an empty object. (However, t is used for JSON's true value.)
;;
;; Note that `json-sexp-mode' inherits from `emacs-lisp-mode' since it's for
;; editing JSON data as Elisp s-expressions.
;;
;;
;; The following commands can be used to manually convert a region or whole
;; buffer from a JSON value to an s-expression and from an s-expression to a
;; JSON value:
;;
;; `json-sexp-convert-region-to-sexp'
;; `json-sexp-convert-region-to-json'
;; `json-sexp-convert-buffer-to-sexp'
;; `json-sexp-convert-buffer-to-json'
;;; Code:
(require 'json)
(defun json-sexp-convert-region-to-sexp (start end)
"Convert region from JSON to sexps."
(interactive "r")
(unless (= start end)
(let ((data (let ((json-object-type 'alist)
(json-false 'false)
(json-null 'null))
(json-read-from-string (buffer-substring start end))))
(point (point)))
(delete-region start end)
(goto-char start)
(insert (pp-to-string data))
;; Only an approximation of our position in the JSON.
(goto-char point))))
(defun json-sexp-convert-region-to-json (start end)
"Convert region from sexps to JSON."
(interactive "r")
(unless (= start end)
(let ((data (car (read-from-string (buffer-substring start end))))
(point (point)))
(delete-region start end)
(goto-char start)
(insert (let ((json-encoding-pretty-print t)
(json-false 'false)
(json-null 'null)
(json-nil 'object))
(json-encode data)))
;; Only an approximation of our position in the s-expression.
(goto-char point))))
(defun json-sexp-convert-buffer-to-sexp ()
"Convert buffer from JSON to sexps."
(interactive)
(json-sexp-convert-region-to-sexp (point-min) (point-max)))
(defun json-sexp-convert-buffer-to-json ()
"Convert buffer from sexps to JSON."
(interactive)
(json-sexp-convert-region-to-json (point-min) (point-max)))
(defvar json-sexp--saved-point nil)
(define-derived-mode json-sexp-mode emacs-lisp-mode "JSON-sexp"
"Major mode for editing JSON in s-expression form.
The buffer-contents, which must be JSON, are transformed to
s-expressions when this mode is started, and transformed back
temporarily to JSON whenever the buffer is saved."
(let ((was-modified (buffer-modified-p)))
(json-sexp-convert-buffer-to-sexp)
(set-buffer-modified-p was-modified))
(add-hook 'before-save-hook 'json-sexp--before-save nil t)
(add-hook 'after-save-hook 'json-sexp--after-save nil t))
(defun json-sexp--before-save ()
(setq json-sexp--saved-point (point))
(json-sexp-convert-buffer-to-json))
(defun json-sexp--after-save ()
(json-sexp-convert-buffer-to-sexp)
(set-buffer-modified-p nil)
(goto-char json-sexp--saved-point))
(provide 'json-sexp-mode)
;;; json-sexp-mode.el ends here
|