Reformat
diff --git a/Cargo.lock b/Cargo.lock
index 6f5db9e..5bc4d9f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3195,10 +3195,22 @@
 [[package]]
 name = "ungrammar"
 version = "1.16.1"
+
+[[package]]
+name = "ungrammar"
+version = "1.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
 
 [[package]]
+name = "ungrammar2json"
+version = "1.0.0"
+dependencies = [
+ "ungrammar 1.16.1",
+ "write-json",
+]
+
+[[package]]
 name = "unicase"
 version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3707,7 +3719,7 @@
  "quote",
  "stdx",
  "time",
- "ungrammar",
+ "ungrammar 1.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "write-json",
  "xflags",
  "xshell",
diff --git a/Cargo.toml b/Cargo.toml
index ecb2686..6f5ea44 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [workspace]
-members = ["xtask/", "lib/*", "crates/*"]
+members = ["xtask/", "lib/*", "lib/ungrammar/ungrammar2json", "crates/*"]
 exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
@@ -42,7 +42,7 @@
 # lsp-server = { path = "lib/lsp-server" }
 
 
-# ungrammar = { path = "../ungrammar" }
+# ungrammar = { path = "lin/ungrammar" }
 
 # salsa = { path = "../salsa" }
 # salsa-macros = { path = "../salsa/components/salsa-macros" }
diff --git a/lib/ungrammar/Cargo.toml b/lib/ungrammar/Cargo.toml
index 920d9ef..6e9dec7 100644
--- a/lib/ungrammar/Cargo.toml
+++ b/lib/ungrammar/Cargo.toml
@@ -8,8 +8,6 @@
 
 exclude = ["/bors.toml", "/.github"]
 
-[workspace]
-members = ["ungrammar2json"]
 
 [dependencies]
 # nope
diff --git a/lib/ungrammar/src/error.rs b/lib/ungrammar/src/error.rs
index 355e0b7..144f9fc 100644
--- a/lib/ungrammar/src/error.rs
+++ b/lib/ungrammar/src/error.rs
@@ -27,10 +27,7 @@
 
 impl Error {
     pub(crate) fn with_location(self, location: Location) -> Error {
-        Error {
-            location: Some(location),
-            ..self
-        }
+        Error { location: Some(location), ..self }
     }
 }
 
diff --git a/lib/ungrammar/src/parser.rs b/lib/ungrammar/src/parser.rs
index a4ce9c1..70fbe1a 100644
--- a/lib/ungrammar/src/parser.rs
+++ b/lib/ungrammar/src/parser.rs
@@ -1,4 +1,5 @@
 //! Simple hand-written ungrammar parser.
+#![allow(clippy::disallowed_types)]
 use std::collections::HashMap;
 
 use crate::{
@@ -36,10 +37,7 @@
 impl Parser {
     fn new(mut tokens: Vec<lexer::Token>) -> Parser {
         tokens.reverse();
-        Parser {
-            tokens,
-            ..Parser::default()
-        }
+        Parser { tokens, ..Parser::default() }
     }
 
     fn peek(&self) -> Option<&lexer::Token> {
@@ -49,9 +47,7 @@
         self.tokens.iter().nth_back(n)
     }
     fn bump(&mut self) -> Result<lexer::Token> {
-        self.tokens
-            .pop()
-            .ok_or_else(|| format_err!("unexpected EOF"))
+        self.tokens.pop().ok_or_else(|| format_err!("unexpected EOF"))
     }
     fn expect(&mut self, kind: TokenKind, what: &str) -> Result<()> {
         let token = self.bump()?;
@@ -75,10 +71,7 @@
         let len = self.node_table.len();
         let grammar = &mut self.grammar;
         *self.node_table.entry(name.clone()).or_insert_with(|| {
-            grammar.nodes.push(NodeData {
-                name,
-                rule: DUMMY_RULE,
-            });
+            grammar.nodes.push(NodeData { name, rule: DUMMY_RULE });
             Node(len)
         })
     }
@@ -127,11 +120,7 @@
         let rule = seq_rule(p)?;
         alt.push(rule)
     }
-    let res = if alt.len() == 1 {
-        alt.pop().unwrap()
-    } else {
-        Rule::Alt(alt)
-    };
+    let res = if alt.len() == 1 { alt.pop().unwrap() } else { Rule::Alt(alt) };
     Ok(res)
 }
 
@@ -142,11 +131,7 @@
     while let Some(rule) = opt_atom_rule(p)? {
         seq.push(rule)
     }
-    let res = if seq.len() == 1 {
-        seq.pop().unwrap()
-    } else {
-        Rule::Seq(seq)
-    };
+    let res = if seq.len() == 1 { seq.pop().unwrap() } else { Rule::Seq(seq) };
     Ok(res)
 }
 
@@ -175,10 +160,7 @@
                         p.bump()?;
                         p.bump()?;
                         let rule = atom_rule(p)?;
-                        let res = Rule::Labeled {
-                            label,
-                            rule: Box::new(rule),
-                        };
+                        let res = Rule::Labeled { label, rule: Box::new(rule) };
                         return Ok(Some(res));
                     }
                     _ => (),
diff --git a/lib/ungrammar/ungrammar2json/src/main.rs b/lib/ungrammar/ungrammar2json/src/main.rs
index f588ed5..3e88458 100644
--- a/lib/ungrammar/ungrammar2json/src/main.rs
+++ b/lib/ungrammar/ungrammar2json/src/main.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::print_stderr, clippy::print_stdout)]
 use std::{
     env,
     io::{self, Read},