Allow comments in setting and keymap JSON files

This commit is contained in:
Max Brunsfeld 2022-04-21 11:58:18 -07:00
parent 066e572767
commit 3a28f09979
10 changed files with 47 additions and 18 deletions

20
Cargo.lock generated
View file

@ -2572,6 +2572,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "json_comments"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ee439ee368ba4a77ac70d04f14015415af8600d6c894dc1f11bd79758c57d5"
[[package]] [[package]]
name = "json_env_logger" name = "json_env_logger"
version = "0.1.1" version = "0.1.1"
@ -2643,7 +2649,7 @@ dependencies = [
"text", "text",
"theme", "theme",
"tree-sitter", "tree-sitter",
"tree-sitter-json", "tree-sitter-json 0.19.0",
"tree-sitter-rust", "tree-sitter-rust",
"unindent", "unindent",
"util", "util",
@ -4304,6 +4310,7 @@ dependencies = [
"assets", "assets",
"collections", "collections",
"gpui", "gpui",
"json_comments",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
@ -5193,6 +5200,15 @@ dependencies = [
"tree-sitter", "tree-sitter",
] ]
[[package]]
name = "tree-sitter-json"
version = "0.20.0"
source = "git+https://github.com/tree-sitter/tree-sitter-json?rev=137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8#137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8"
dependencies = [
"cc",
"tree-sitter",
]
[[package]] [[package]]
name = "tree-sitter-markdown" name = "tree-sitter-markdown"
version = "0.0.1" version = "0.0.1"
@ -5837,7 +5853,7 @@ dependencies = [
"toml", "toml",
"tree-sitter", "tree-sitter",
"tree-sitter-c", "tree-sitter-c",
"tree-sitter-json", "tree-sitter-json 0.20.0",
"tree-sitter-markdown", "tree-sitter-markdown",
"tree-sitter-rust", "tree-sitter-rust",
"tree-sitter-typescript", "tree-sitter-typescript",

View file

@ -17,6 +17,7 @@ gpui = { path = "../gpui" }
theme = { path = "../theme" } theme = { path = "../theme" }
util = { path = "../util" } util = { path = "../util" }
anyhow = "1.0.38" anyhow = "1.0.38"
json_comments = "0.2"
schemars = "0.8" schemars = "0.8"
serde = { version = "1", features = ["derive", "rc"] } serde = { version = "1", features = ["derive", "rc"] }
serde_json = { version = "1.0.64", features = ["preserve_order"] } serde_json = { version = "1.0.64", features = ["preserve_order"] }

View file

@ -1,3 +1,4 @@
use crate::parse_json_with_comments;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use assets::Assets; use assets::Assets;
use collections::BTreeMap; use collections::BTreeMap;
@ -7,14 +8,14 @@ use serde_json::value::RawValue;
#[derive(Deserialize, Default, Clone)] #[derive(Deserialize, Default, Clone)]
#[serde(transparent)] #[serde(transparent)]
pub struct KeymapFile(BTreeMap<String, ActionsByKeystroke>); pub struct KeymapFileContent(BTreeMap<String, ActionsByKeystroke>);
type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>; type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>;
#[derive(Deserialize)] #[derive(Deserialize)]
struct ActionWithData<'a>(#[serde(borrow)] &'a str, #[serde(borrow)] &'a RawValue); struct ActionWithData(Box<str>, Box<RawValue>);
impl KeymapFile { impl KeymapFileContent {
pub fn load_defaults(cx: &mut MutableAppContext) { pub fn load_defaults(cx: &mut MutableAppContext) {
for path in ["keymaps/default.json", "keymaps/vim.json"] { for path in ["keymaps/default.json", "keymaps/vim.json"] {
Self::load(path, cx).unwrap(); Self::load(path, cx).unwrap();
@ -24,7 +25,7 @@ impl KeymapFile {
pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> { pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
let content = Assets::get(asset_path).unwrap().data; let content = Assets::get(asset_path).unwrap().data;
let content_str = std::str::from_utf8(content.as_ref()).unwrap(); let content_str = std::str::from_utf8(content.as_ref()).unwrap();
Ok(serde_json::from_str::<Self>(content_str)?.add(cx)?) Ok(parse_json_with_comments::<Self>(content_str)?.add(cx)?)
} }
pub fn add(self, cx: &mut MutableAppContext) -> Result<()> { pub fn add(self, cx: &mut MutableAppContext) -> Result<()> {
@ -42,7 +43,7 @@ impl KeymapFile {
// string. But `RawValue` currently does not work inside of an untagged enum. // string. But `RawValue` currently does not work inside of an untagged enum.
let action = if action.starts_with('[') { let action = if action.starts_with('[') {
let ActionWithData(name, data) = serde_json::from_str(action)?; let ActionWithData(name, data) = serde_json::from_str(action)?;
cx.deserialize_action(name, Some(data.get())) cx.deserialize_action(&name, Some(data.get()))
} else { } else {
let name = serde_json::from_str(action)?; let name = serde_json::from_str(action)?;
cx.deserialize_action(name, None) cx.deserialize_action(name, None)

View file

@ -9,13 +9,13 @@ use schemars::{
}, },
JsonSchema, JsonSchema,
}; };
use serde::Deserialize; use serde::{de::DeserializeOwned, Deserialize};
use serde_json::Value; use serde_json::Value;
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use theme::{Theme, ThemeRegistry}; use theme::{Theme, ThemeRegistry};
use util::ResultExt as _; use util::ResultExt as _;
pub use keymap_file::KeymapFile; pub use keymap_file::KeymapFileContent;
#[derive(Clone)] #[derive(Clone)]
pub struct Settings { pub struct Settings {
@ -260,3 +260,9 @@ fn merge_option<T: Copy>(target: &mut Option<T>, value: Option<T>) {
*target = value; *target = value;
} }
} }
pub fn parse_json_with_comments<T: DeserializeOwned>(content: &str) -> Result<T> {
Ok(serde_json::from_reader(
json_comments::CommentSettings::c_style().strip_comments(content.as_bytes()),
)?)
}

View file

@ -24,7 +24,7 @@ impl<'a> VimTestContext<'a> {
editor::init(cx); editor::init(cx);
crate::init(cx); crate::init(cx);
settings::KeymapFile::load("keymaps/vim.json", cx).unwrap(); settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap();
}); });
let params = cx.update(WorkspaceParams::test); let params = cx.update(WorkspaceParams::test);

View file

@ -86,7 +86,7 @@ tiny_http = "0.8"
toml = "0.5" toml = "0.5"
tree-sitter = "0.20.4" tree-sitter = "0.20.4"
tree-sitter-c = "0.20.1" tree-sitter-c = "0.20.1"
tree-sitter-json = "0.19.0" tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8" }
tree-sitter-rust = "0.20.1" tree-sitter-rust = "0.20.1"
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" } tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
tree-sitter-typescript = "0.20.1" tree-sitter-typescript = "0.20.1"

View file

@ -1,3 +1,5 @@
(comment) @comment
(string) @string (string) @string
(pair (pair

View file

@ -17,7 +17,7 @@ use gpui::{App, AssetSource, AsyncAppContext, Task};
use log::LevelFilter; use log::LevelFilter;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::Fs; use project::Fs;
use settings::{self, KeymapFile, Settings, SettingsFileContent}; use settings::{self, KeymapFileContent, Settings, SettingsFileContent};
use smol::process::Command; use smol::process::Command;
use std::{env, fs, path::PathBuf, sync::Arc, thread, time::Duration}; use std::{env, fs, path::PathBuf, sync::Arc, thread, time::Duration};
use theme::{ThemeRegistry, DEFAULT_THEME_NAME}; use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
@ -309,7 +309,7 @@ fn load_config_files(
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
) -> oneshot::Receiver<( ) -> oneshot::Receiver<(
WatchedJsonFile<SettingsFileContent>, WatchedJsonFile<SettingsFileContent>,
WatchedJsonFile<KeymapFile>, WatchedJsonFile<KeymapFileContent>,
)> { )> {
let executor = app.background(); let executor = app.background();
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();

View file

@ -4,7 +4,7 @@ use postage::sink::Sink as _;
use postage::{prelude::Stream, watch}; use postage::{prelude::Stream, watch};
use project::Fs; use project::Fs;
use serde::Deserialize; use serde::Deserialize;
use settings::{KeymapFile, Settings, SettingsFileContent}; use settings::{parse_json_with_comments, KeymapFileContent, Settings, SettingsFileContent};
use std::{path::Path, sync::Arc, time::Duration}; use std::{path::Path, sync::Arc, time::Duration};
use theme::ThemeRegistry; use theme::ThemeRegistry;
use util::ResultExt; use util::ResultExt;
@ -44,7 +44,7 @@ where
fs.load(&path) fs.load(&path)
.await .await
.log_err() .log_err()
.and_then(|data| serde_json::from_str(&data).log_err()) .and_then(|data| parse_json_with_comments(&data).log_err())
} else { } else {
Some(T::default()) Some(T::default())
} }
@ -76,11 +76,14 @@ pub fn settings_from_files(
}) })
} }
pub async fn watch_keymap_file(mut file: WatchedJsonFile<KeymapFile>, mut cx: AsyncAppContext) { pub async fn watch_keymap_file(
mut file: WatchedJsonFile<KeymapFileContent>,
mut cx: AsyncAppContext,
) {
while let Some(content) = file.0.recv().await { while let Some(content) = file.0.recv().await {
cx.update(|cx| { cx.update(|cx| {
cx.clear_bindings(); cx.clear_bindings();
settings::KeymapFile::load_defaults(cx); settings::KeymapFileContent::load_defaults(cx);
content.add(cx).log_err(); content.add(cx).log_err();
}); });
} }

View file

@ -138,7 +138,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
workspace::lsp_status::init(cx); workspace::lsp_status::init(cx);
settings::KeymapFile::load_defaults(cx); settings::KeymapFileContent::load_defaults(cx);
} }
pub fn build_workspace( pub fn build_workspace(