From ff35fbca2ff8b818ce47efe2bb1d07f5f70a6051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sat, 17 Oct 2015 17:15:23 +0200 Subject: [PATCH 1/2] Add json-sexp-mode. --- packages/json-sexp-mode/json-sexp-mode.el | 110 ++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 packages/json-sexp-mode/json-sexp-mode.el diff --git a/packages/json-sexp-mode/json-sexp-mode.el b/packages/json-sexp-mode/json-sexp-mode.el new file mode 100644 index 0000000..689ba8c --- /dev/null +++ b/packages/json-sexp-mode/json-sexp-mode.el @@ -0,0 +1,110 @@ +;;; json-sexp-mode.el --- Edit JSON in s-expression form. + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Taylan Ulrich Bayırlı/Kammer +;; 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 . + +;;; 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.) +;; +;; +;; 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 prog-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." + (lisp-mode-variables nil nil 'elisp) + (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 -- 2.5.0