Json Emacs中类似模型/视图的编辑
我有一些JSON文件,我正在编写一种模式,允许编辑JSON对象的单个属性,而不依赖于其他属性。例如: foo.json:Json Emacs中类似模型/视图的编辑,json,model-view-controller,emacs,elisp,Json,Model View Controller,Emacs,Elisp,我有一些JSON文件,我正在编写一种模式,允许编辑JSON对象的单个属性,而不依赖于其他属性。例如: foo.json: { "creation_timestamp": "1411210038.000000", "description": "lorem ipsum.\ndolor sit amet.", "version": 4 } 打开foo.json将导致此缓冲区: lorem ipsum. dolor sit amet. 将第一行更改为“foo bar”并保存文件将导致
{
"creation_timestamp": "1411210038.000000",
"description": "lorem ipsum.\ndolor sit amet.",
"version": 4
}
打开foo.json将导致此缓冲区:
lorem ipsum.
dolor sit amet.
将第一行更改为“foo bar”并保存文件将导致foo.json
中只更新了说明
字段:
{
"creation_timestamp": "1411210038.000000",
"description": "foo bar.\ndolor sit amet.",
"version": 4
}
最好的策略是什么?我目前的努力是:
说明属性的值,创建一个“视图”
localwrite文件
hook终止“视图”,更新覆盖中的json,并保存文件。保存后的钩子将重新创建“视图”,以便用户可以继续编辑
这是一个冗长而脆弱的过程。有没有更好的方法来处理屏幕表示形式与磁盘表示形式不同的数据?您的用例真的像您描述的场景一样简单(不是解决方案大纲,而是问题/用例)
如果是这样的话,你的解决方案听起来像是矫枉过正。如果用例像编辑特定键的值一样简单,我可能会这样做:
在临时缓冲区中显示该字段的内容(对应于键的值),以便编辑
绑定一个键(例如,C-C-C
),将编辑的值保存回文件
例如,我在中这样做是为了编辑书签的标记(以及使用不同的命令编辑书签的所有字段)。编辑标签的命令是bmkp edit tags
。命令(绑定到编辑缓冲区中的C-C-C
)是bmkp edit tags send
。在上下文中,代码是。以下是断章取义的:
(defmacro bmkp,输出到普通温度缓冲区(buf和静止体)
类似于“输出到临时缓冲区”,但没有“*Help*”导航内容
`(展开保护)
(项目
(删除挂钩“临时缓冲区设置挂钩”帮助模式设置)
(移除挂钩“临时缓冲区显示挂钩”帮助模式完成)
(输出至温度缓冲器,buf,@body))
(添加挂钩“临时缓冲区设置挂钩”帮助模式设置)
(添加挂钩“临时缓冲区显示挂钩”帮助模式完成)))
(定义派生模式bmkp编辑标记模式emacs lisp模式
“编辑书签标记”
“编辑书签标记的模式。
完成撰写后,键入\\[bmkp编辑标记发送]。”
:组“书签+)
;; 此绑定必须在*模式之后定义,因此定义了“bmkp edit tags mode map”。
;; (或者,我们可以使用'defvar'在之前定义'bmkp edit tags mode map'
;调用“定义派生模式”。)
(定义键bmkp编辑标记模式映射“\C-C\C-C””bmkp编辑标记发送)
(定义bmkp编辑标记(书签);绑定到'C-x p t e'
“编辑书签的标记,并可能保存结果。
编辑的值必须是一个列表,其每个元素都是
字符串或键为字符串的cons。
书签是书签名称或书签记录。“
(交互式(列表(书签完成阅读“编辑书签标签”(bmkp默认书签名称)))
(setq书签(bmkp在列表书签中获取书签))
(let*((btags(bmkp get tags书签))
(bmkname(来自记录书签的bmkp书签名称))
(edbuf(格式“*编辑书签“%s”*“bmkname”的标记)))
(setq bmkp返回缓冲区(当前缓冲区))
(bmkp,输出到普通温度缓冲器edbuf
(普林斯)
(替换命令键
(concat;;编辑书签的标记\n;;\n;;\“bmkname”\“\n;;\n”
“;;编辑的值必须是一个列表,其中每个元素都是\n”
;;字符串或其键为字符串的cons。\n;;\n
;;不要修改这些注释。\n;;\n
“;完成后键入\\`\\[bmkp编辑标记发送]。\n\n”))
(让((打印圆圈bmkp属性书签名称标志))(pp btags))
(转到字符(最小点)))
(pop至缓冲区edbuf)
(缓冲区启用撤消)
(使用当前缓冲区(获取缓冲区edbuf)(bmkp编辑标记模式)))
(取消bmkp编辑标记发送(&可选batchp)
“使用缓冲区内容作为书签标记的内部形式。
不要修改以“;;”开头的标题注释行
(互动)
(除非(eq主模式“bmkp编辑标记模式”(错误“不在“bmkp编辑标记模式”中))
(let(bname)
(展开保护)
(let(标记bmk)
(转到字符(最小点))
(除非(向前搜索“;编辑书签标记”;\n;;\n;;”)
(错误“编辑缓冲区中缺少标头”))
(除非是(stringp(setq bname)(读取(当前缓冲区)))
(错误“编辑缓冲区标头中的书签名称错误”))
(除非(setq bmk(bmkp在列表bname'NOERROR中获取书签))
(错误“没有这样的书签:`%s'”bname))
(除非(bmkp书签类型bmk)(错误“无效书签”))
(转到字符(最小点))
(setq标签(读取(当前缓冲区)))
(除非(listp标记)(错误“tags sexp不是字符串列表或带有字符串键的列表”))
(书签道具集bmk标签)
(setq bname(来自记录bmk的bmkp书签名称))
(bmkp记录访问bmk batchp)
(bmkp刷新/重建菜单列表bname batchp)
(bmkp可能会保存书签)
(除非是batchp(消息“已更新书签文件,带有已编辑标记”))
(终止缓冲区(当前缓冲区)))
(当bmkp返回缓冲区时)
(pop到缓冲区bmkp返回缓冲区)
(当(等于(缓冲区名称(当前缓冲区))“*书签列表*”)
(bmkp bmenu转到名为bname(()()))的书签)
最相关的位是:
定义启动编辑的命令和结束编辑并保存更改的命令。 (defmacro bmkp-with-output-to-plain-temp-buffer (buf &rest body)
"Like `with-output-to-temp-buffer', but with no `*Help*' navigation stuff."
`(unwind-protect
(progn
(remove-hook 'temp-buffer-setup-hook 'help-mode-setup)
(remove-hook 'temp-buffer-show-hook 'help-mode-finish)
(with-output-to-temp-buffer ,buf ,@body))
(add-hook 'temp-buffer-setup-hook 'help-mode-setup)
(add-hook 'temp-buffer-show-hook 'help-mode-finish)))
(define-derived-mode bmkp-edit-tags-mode emacs-lisp-mode
"Edit Bookmark Tags"
"Mode for editing bookmark tags.
When you have finished composing, type \\[bmkp-edit-tags-send]."
:group 'bookmark-plus)
;; This binding must be defined *after* the mode, so `bmkp-edit-tags-mode-map' is defined.
;; (Alternatively, we could use a `defvar' to define `bmkp-edit-tags-mode-map' before
;; calling `define-derived-mode'.)
(define-key bmkp-edit-tags-mode-map "\C-c\C-c" 'bmkp-edit-tags-send)
(defun bmkp-edit-tags (bookmark) ; Bound to `C-x p t e'
"Edit BOOKMARK's tags, and maybe save the result.
The edited value must be a list each of whose elements is either a
string or a cons whose key is a string.
BOOKMARK is a bookmark name or a bookmark record."
(interactive (list (bookmark-completing-read "Edit tags for bookmark" (bmkp-default-bookmark-name))))
(setq bookmark (bmkp-get-bookmark-in-alist bookmark))
(let* ((btags (bmkp-get-tags bookmark))
(bmkname (bmkp-bookmark-name-from-record bookmark))
(edbuf (format "*Edit Tags for Bookmark `%s'*" bmkname)))
(setq bmkp-return-buffer (current-buffer))
(bmkp-with-output-to-plain-temp-buffer edbuf
(princ
(substitute-command-keys
(concat ";; Edit tags for bookmark\n;;\n;; \"" bmkname "\"\n;;\n"
";; The edited value must be a list each of whose elements is\n"
";; either a string or a cons whose key is a string.\n;;\n"
";; DO NOT MODIFY THESE COMMENTS.\n;;\n"
";; Type \\<bmkp-edit-tags-mode-map>`\\[bmkp-edit-tags-send]' when done.\n\n")))
(let ((print-circle bmkp-propertize-bookmark-names-flag)) (pp btags))
(goto-char (point-min)))
(pop-to-buffer edbuf)
(buffer-enable-undo)
(with-current-buffer (get-buffer edbuf) (bmkp-edit-tags-mode))))
(defun bmkp-edit-tags-send (&optional batchp)
"Use buffer contents as the internal form of a bookmark's tags.
DO NOT MODIFY the header comment lines, which begin with `;;'."
(interactive)
(unless (eq major-mode 'bmkp-edit-tags-mode) (error "Not in `bmkp-edit-tags-mode'"))
(let (bname)
(unwind-protect
(let (tags bmk)
(goto-char (point-min))
(unless (search-forward ";; Edit tags for bookmark\n;;\n;; ")
(error "Missing header in edit buffer"))
(unless (stringp (setq bname (read (current-buffer))))
(error "Bad bookmark name in edit-buffer header"))
(unless (setq bmk (bmkp-get-bookmark-in-alist bname 'NOERROR))
(error "No such bookmark: `%s'" bname))
(unless (bmkp-bookmark-type bmk) (error "Invalid bookmark"))
(goto-char (point-min))
(setq tags (read (current-buffer)))
(unless (listp tags) (error "Tags sexp is not a list of strings or an alist with string keys"))
(bookmark-prop-set bmk 'tags tags)
(setq bname (bmkp-bookmark-name-from-record bmk))
(bmkp-record-visit bmk batchp)
(bmkp-refresh/rebuild-menu-list bname batchp)
(bmkp-maybe-save-bookmarks)
(unless batchp (message "Updated bookmark file with edited tags")))
(kill-buffer (current-buffer)))
(when bmkp-return-buffer
(pop-to-buffer bmkp-return-buffer)
(when (equal (buffer-name (current-buffer)) "*Bookmark List*")
(bmkp-bmenu-goto-bookmark-named bname)))))