Compare commits
10 Commits
inline-ass
...
configurat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52afd4720c | ||
|
|
773c1f16e3 | ||
|
|
42ab97f6a8 | ||
|
|
2d74297317 | ||
|
|
ff027f1570 | ||
|
|
aeff2c633c | ||
|
|
788a6ae14a | ||
|
|
8cef8da0e7 | ||
|
|
6602f7b2b6 | ||
|
|
39d08e1577 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -13735,6 +13735,8 @@ dependencies = [
|
||||
"cargo_metadata",
|
||||
"cargo_toml",
|
||||
"clap",
|
||||
"schemars",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -8,7 +8,7 @@ mod zed;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use assistant::PromptBuilder;
|
||||
use clap::{command, Parser};
|
||||
use clap::{command, Parser, ValueEnum};
|
||||
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
|
||||
use client::{parse_zed_link, Client, DevServerToken, UserStore};
|
||||
use collab_ui::channel_view::ChannelView;
|
||||
@@ -19,7 +19,7 @@ use fs::{Fs, RealFs};
|
||||
use futures::{future, StreamExt};
|
||||
use git::GitHostingProviderRegistry;
|
||||
use gpui::{
|
||||
Action, App, AppContext, AsyncAppContext, Context, DismissEvent, Global, Task,
|
||||
Action, App, AppContext, AsyncAppContext, Context, DismissEvent, Global, ReadGlobal as _, Task,
|
||||
UpdateGlobal as _, VisualContext,
|
||||
};
|
||||
use image_viewer;
|
||||
@@ -536,19 +536,45 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let app_state = app_state.clone();
|
||||
let state = app_state.clone();
|
||||
let prompt_builder = prompt_builder.clone();
|
||||
cx.spawn(move |cx| async move {
|
||||
while let Some(urls) = open_rx.next().await {
|
||||
cx.update(|cx| {
|
||||
if let Some(request) = OpenRequest::parse(urls, cx).log_err() {
|
||||
handle_open_request(request, app_state.clone(), prompt_builder.clone(), cx);
|
||||
handle_open_request(request, state.clone(), prompt_builder.clone(), cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
if let Some(schema) = args.schema {
|
||||
let app_state = app_state.clone();
|
||||
cx.spawn(|cx| async move {
|
||||
match schema {
|
||||
SchemaKind::Settings => {
|
||||
let language_names = app_state.languages.language_names();
|
||||
let schema = cx.update(|cx| {
|
||||
SettingsStore::global(cx).json_schema(
|
||||
&settings::SettingsJsonSchemaParams {
|
||||
staff_mode: false,
|
||||
language_names: &language_names,
|
||||
font_names: &[],
|
||||
},
|
||||
cx,
|
||||
)
|
||||
});
|
||||
if let Ok(schema) = schema {
|
||||
if let Ok(schema) = serde_json::to_string(&schema) {
|
||||
let _ = std::fs::write("settings-schema.json", &(schema));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1039,6 +1065,11 @@ fn stdout_is_a_pty() -> bool {
|
||||
std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_none() && std::io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, ValueEnum)]
|
||||
enum SchemaKind {
|
||||
Settings,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "zed", disable_version_flag = true)]
|
||||
struct Args {
|
||||
@@ -1053,6 +1084,10 @@ struct Args {
|
||||
/// Instructs zed to run as a dev server on this machine. (not implemented)
|
||||
#[arg(long)]
|
||||
dev_server_token: Option<String>,
|
||||
|
||||
/// Instructs zed to dump a JSON schema to a file.
|
||||
#[arg(long)]
|
||||
schema: Option<SchemaKind>,
|
||||
}
|
||||
|
||||
fn parse_url_arg(arg: &str, cx: &AppContext) -> Result<String> {
|
||||
|
||||
@@ -9,8 +9,8 @@ site-url = "/docs/"
|
||||
[output.html]
|
||||
no-section-label = true
|
||||
preferred-dark-theme = "light"
|
||||
additional-css = ["theme/page-toc.css", "theme/plugins.css"]
|
||||
additional-js = ["theme/page-toc.js", "theme/plugins.js"]
|
||||
additional-css = ["theme/page-toc.css", "theme/settings-table.css", "theme/plugins.css"]
|
||||
additional-js = ["theme/page-toc.js", "theme/settings-table.js", "theme/plugins.js"]
|
||||
|
||||
[output.html.print]
|
||||
enable = false
|
||||
|
||||
@@ -29,6 +29,8 @@ Extensions that provide language servers may also provide default settings for t
|
||||
|
||||
# Settings
|
||||
|
||||
<div id="settings-container"></div>
|
||||
|
||||
## Active Pane Magnification
|
||||
|
||||
- Description: Scale by which to zoom the active pane. When set to `1.0`, the active pane has the same size as others, but when set to a larger value, the active pane takes up more space.
|
||||
|
||||
4
docs/theme/css/variables.css
vendored
4
docs/theme/css/variables.css
vendored
@@ -44,8 +44,8 @@
|
||||
--warning-bg: hsl(42, 100%, 60%, 0.1);
|
||||
--warning-icon: hsl(42, 100%, 30%);
|
||||
|
||||
--table-border-color: hsl(219, 93%, 42%, 0.15);
|
||||
--table-header-bg: hsl(0, 0%, 80%);
|
||||
--table-border-color: hsl(219, 10%, 42%, 0.15);
|
||||
--table-header-bg: hsl(219, 18%, 68%, 0.15);
|
||||
--table-alternate-bg: hsl(0, 0%, 97%);
|
||||
|
||||
--searchbar-border-color: #aaa;
|
||||
|
||||
95
docs/theme/settings-table.css
vendored
Normal file
95
docs/theme/settings-table.css
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
.settings-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: var(--font);
|
||||
color: var(--fg);
|
||||
background-color: var(--bg);
|
||||
}
|
||||
|
||||
.setting-container {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
}
|
||||
|
||||
.setting-header {
|
||||
grid-column: span 2 / span 2;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.8rem;
|
||||
padding: 0.5em 1em 0.5rem 0;
|
||||
}
|
||||
|
||||
.setting-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 2rem;
|
||||
/* padding: 0.5em 1em; */
|
||||
}
|
||||
|
||||
.setting-name {
|
||||
font-family: monospace;
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: var(--sidebar-fg);
|
||||
}
|
||||
|
||||
.setting-type {
|
||||
font-family: monospace;
|
||||
font-size: 1.3rem;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.setting-description {
|
||||
font-size: 1.3rem;
|
||||
color: var(--fg);
|
||||
padding: 0.5em 0 0.5em 0;
|
||||
}
|
||||
|
||||
.setting-default {
|
||||
font-family: monospace;
|
||||
font-size: 1.3rem;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.setting-status {
|
||||
width: fit-content;
|
||||
padding: 0.2em 0.5em;
|
||||
background-color: var(--sidebar-active-bg);
|
||||
font-size: 1.2rem;
|
||||
font-family: monospace;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.setting-details {
|
||||
grid-column: span 4 / span 4;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.setting-details tr:nth-child(even) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.setting-details td {
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 1.2rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.setting-value {
|
||||
font-size: 1.4rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.settings-list code {
|
||||
font-family: var(--mono-font);
|
||||
font-size: 1.4rem;
|
||||
background-color: var(--quote-bg);
|
||||
padding: 2px 4px;
|
||||
border-radius: 3px;
|
||||
color: var(--inline-code-color);
|
||||
}
|
||||
1448
docs/theme/settings-table.js
vendored
Normal file
1448
docs/theme/settings-table.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,3 +13,5 @@ anyhow.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
cargo_toml.workspace = true
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
schemars.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -18,6 +18,8 @@ enum CliCommand {
|
||||
Licenses(tasks::licenses::LicensesArgs),
|
||||
/// Checks that packages conform to a set of standards.
|
||||
PackageConformity(tasks::package_conformity::PackageConformityArgs),
|
||||
/// Checks that settings schema conforms to a set of standards.
|
||||
ValidateSchema(tasks::validate_schema::SchemaValidationArgs),
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
@@ -29,5 +31,6 @@ fn main() -> Result<()> {
|
||||
CliCommand::PackageConformity(args) => {
|
||||
tasks::package_conformity::run_package_conformity(args)
|
||||
}
|
||||
CliCommand::ValidateSchema(args) => tasks::validate_schema::run_validate_schema(args),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod clippy;
|
||||
pub mod licenses;
|
||||
pub mod package_conformity;
|
||||
pub mod validate_schema;
|
||||
|
||||
128
tooling/xtask/src/tasks/validate_schema.rs
Normal file
128
tooling/xtask/src/tasks/validate_schema.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use schemars::{
|
||||
schema::{RootSchema, SchemaObject},
|
||||
visit::Visitor,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub struct SchemaValidationArgs {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Violation {
|
||||
MissingDefault,
|
||||
MissingExample,
|
||||
MissingMetadata,
|
||||
MissingDescription,
|
||||
}
|
||||
struct Violations {
|
||||
schema: SchemaObject,
|
||||
violations: Vec<(Vec<String>, Violation)>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct SettingsSchemaValidator {
|
||||
objects: Vec<Violations>,
|
||||
}
|
||||
|
||||
impl SettingsSchemaValidator {
|
||||
fn validate_schema_object(&mut self, builder: &mut ViolationsBuilder, schema: &SchemaObject) {
|
||||
if schema.metadata.is_none() {
|
||||
builder.add(Violation::MissingMetadata);
|
||||
} else if let Some(metadata) = &schema.metadata {
|
||||
if metadata.description.is_none() {
|
||||
builder.add(Violation::MissingDescription);
|
||||
}
|
||||
if metadata.default.is_none() {
|
||||
builder.add(Violation::MissingDefault);
|
||||
}
|
||||
if metadata.examples.is_empty() && !Self::is_boolean_schema(schema) {
|
||||
builder.add(Violation::MissingExample);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(object) = &schema.object {
|
||||
for (property, property_schema) in &object.properties {
|
||||
builder.push(property.clone());
|
||||
self.validate_schema_object(builder, &property_schema.clone().into_object());
|
||||
builder.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_boolean_schema(schema: &SchemaObject) -> bool {
|
||||
schema.instance_type == Some(schemars::schema::InstanceType::Boolean.into())
|
||||
}
|
||||
}
|
||||
|
||||
struct ViolationsBuilder<'a> {
|
||||
violations: &'a mut Violations,
|
||||
current_path: Vec<String>,
|
||||
}
|
||||
|
||||
impl<'a> ViolationsBuilder<'a> {
|
||||
fn new(violations: &'a mut Violations) -> Self {
|
||||
Self {
|
||||
violations,
|
||||
current_path: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, violation: Violation) {
|
||||
self.violations
|
||||
.violations
|
||||
.push((self.current_path.clone(), violation));
|
||||
}
|
||||
|
||||
fn push(&mut self, segment: String) {
|
||||
self.current_path.push(segment);
|
||||
}
|
||||
|
||||
fn pop(&mut self) {
|
||||
self.current_path.pop();
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor for SettingsSchemaValidator {
|
||||
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
|
||||
let mut violations = Violations {
|
||||
schema: schema.clone(),
|
||||
violations: Vec::new(),
|
||||
};
|
||||
let mut builder = ViolationsBuilder::new(&mut violations);
|
||||
|
||||
self.validate_schema_object(&mut builder, schema);
|
||||
|
||||
if !violations.violations.is_empty() {
|
||||
self.objects.push(violations);
|
||||
}
|
||||
|
||||
schemars::visit::visit_schema_object(self, schema)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_validate_schema(args: SchemaValidationArgs) -> Result<()> {
|
||||
let contents = std::fs::read_to_string(args.path)?;
|
||||
let mut schema: RootSchema = serde_json::from_str(&contents)?;
|
||||
let mut validator = SettingsSchemaValidator::default();
|
||||
validator.visit_root_schema(&mut schema);
|
||||
|
||||
let total_violations: usize = validator.objects.iter().map(|v| v.violations.len()).sum();
|
||||
println!("Total violations found: {}", total_violations);
|
||||
|
||||
for violation in validator.objects.iter().flat_map(|v| &v.violations) {
|
||||
let path_str = if violation.0.is_empty() {
|
||||
"<root>".to_string()
|
||||
} else {
|
||||
violation.0.join(".")
|
||||
};
|
||||
println!("{}: {:?}", path_str, violation.1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user