Merge remote-tracking branch 'origin/main' into assistant-2

This commit is contained in:
Antonio Scandurra 2023-06-07 09:34:16 +02:00
commit 0dae8f2dd8
35 changed files with 343 additions and 238 deletions

21
Cargo.lock generated
View file

@ -100,7 +100,6 @@ name = "ai"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets",
"chrono", "chrono",
"collections", "collections",
"editor", "editor",
@ -220,15 +219,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16"
[[package]]
name = "assets"
version = "0.1.0"
dependencies = [
"anyhow",
"gpui",
"rust-embed",
]
[[package]] [[package]]
name = "async-broadcast" name = "async-broadcast"
version = "0.4.1" version = "0.4.1"
@ -1429,7 +1419,6 @@ name = "copilot_button"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets",
"context_menu", "context_menu",
"copilot", "copilot",
"editor", "editor",
@ -6151,7 +6140,6 @@ name = "settings"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets",
"collections", "collections",
"fs", "fs",
"futures 0.3.28", "futures 0.3.28",
@ -6160,6 +6148,7 @@ dependencies = [
"lazy_static", "lazy_static",
"postage", "postage",
"pretty_assertions", "pretty_assertions",
"rust-embed",
"schemars", "schemars",
"serde", "serde",
"serde_derive", "serde_derive",
@ -7404,8 +7393,8 @@ dependencies = [
[[package]] [[package]]
name = "tree-sitter-elixir" name = "tree-sitter-elixir"
version = "0.19.0" version = "0.1.0"
source = "git+https://github.com/elixir-lang/tree-sitter-elixir?rev=05e3631c6a0701c1fa518b0fee7be95a2ceef5e2#05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" source = "git+https://github.com/elixir-lang/tree-sitter-elixir?rev=4ba9dab6e2602960d95b2b625f3386c27e08084e#4ba9dab6e2602960d95b2b625f3386c27e08084e"
dependencies = [ dependencies = [
"cc", "cc",
"tree-sitter", "tree-sitter",
@ -7801,6 +7790,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"rand 0.8.5", "rand 0.8.5",
"rust-embed",
"serde", "serde",
"serde_json", "serde_json",
"smol", "smol",
@ -7871,7 +7861,6 @@ name = "vim"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets",
"async-compat", "async-compat",
"async-trait", "async-trait",
"collections", "collections",
@ -8699,7 +8688,6 @@ name = "workspace"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assets",
"async-recursion 1.0.4", "async-recursion 1.0.4",
"bincode", "bincode",
"call", "call",
@ -8799,7 +8787,6 @@ dependencies = [
"activity_indicator", "activity_indicator",
"ai", "ai",
"anyhow", "anyhow",
"assets",
"async-compression", "async-compression",
"async-recursion 0.3.2", "async-recursion 0.3.2",
"async-tar", "async-tar",

View file

@ -2,7 +2,6 @@
members = [ members = [
"crates/activity_indicator", "crates/activity_indicator",
"crates/ai", "crates/ai",
"crates/assets",
"crates/auto_update", "crates/auto_update",
"crates/breadcrumbs", "crates/breadcrumbs",
"crates/call", "crates/call",
@ -88,6 +87,7 @@ parking_lot = { version = "0.11.1" }
postage = { version = "0.5", features = ["futures-traits"] } postage = { version = "0.5", features = ["futures-traits"] }
rand = { version = "0.8.5" } rand = { version = "0.8.5" }
regex = { version = "1.5" } regex = { version = "1.5" }
rust-embed = { version = "6.3", features = ["include-exclude"] }
schemars = { version = "0.8" } schemars = { version = "0.8" }
serde = { version = "1.0", features = ["derive", "rc"] } serde = { version = "1.0", features = ["derive", "rc"] }
serde_derive = { version = "1.0", features = ["deserialize_in_place"] } serde_derive = { version = "1.0", features = ["deserialize_in_place"] }
@ -116,3 +116,4 @@ split-debuginfo = "unpacked"
[profile.release] [profile.release]
debug = true debug = true
lto = "thin"

View file

@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.2 # syntax = docker/dockerfile:1.2
FROM rust:1.65-bullseye as builder FROM rust:1.70-bullseye as builder
WORKDIR app WORKDIR app
COPY . . COPY . .

View file

@ -1,7 +1,7 @@
// Zed settings // Folder-specific settings
// //
// For information on how to configure Zed, see the Zed // For a full list of overridable settings, and general information on folder-specific settings, see the documentation:
// documentation: https://zed.dev/docs/configuring-zed // https://docs.zed.dev/configuration/configuring-zed#folder-specific-settings
// //
// To see all of Zed's default settings without changing your // To see all of Zed's default settings without changing your
// custom settings, run the `open default settings` command // custom settings, run the `open default settings` command

View file

@ -9,7 +9,6 @@ path = "src/ai.rs"
doctest = false doctest = false
[dependencies] [dependencies]
assets = { path = "../assets"}
collections = { path = "../collections"} collections = { path = "../collections"}
editor = { path = "../editor" } editor = { path = "../editor" }
fs = { path = "../fs" } fs = { path = "../fs" }

View file

@ -1,14 +0,0 @@
[package]
name = "assets"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
path = "src/assets.rs"
doctest = false
[dependencies]
gpui = { path = "../gpui" }
anyhow.workspace = true
rust-embed = { version = "6.3", features = ["include-exclude"] }

View file

@ -1,29 +0,0 @@
use std::process::Command;
fn main() {
let output = Command::new("npm")
.current_dir("../../styles")
.args(["install", "--no-save"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"failed to install theme dependencies {}",
String::from_utf8_lossy(&output.stderr)
);
}
let output = Command::new("npm")
.current_dir("../../styles")
.args(["run", "build"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"build script failed {}",
String::from_utf8_lossy(&output.stderr)
);
}
println!("cargo:rerun-if-changed=../../styles/src");
}

View file

@ -9,7 +9,6 @@ path = "src/copilot_button.rs"
doctest = false doctest = false
[dependencies] [dependencies]
assets = { path = "../assets" }
copilot = { path = "../copilot" } copilot = { path = "../copilot" }
editor = { path = "../editor" } editor = { path = "../editor" }
fs = { path = "../fs" } fs = { path = "../fs" }

View file

@ -315,9 +315,7 @@ async fn configure_disabled_globs(
let settings_editor = workspace let settings_editor = workspace
.update(&mut cx, |_, cx| { .update(&mut cx, |_, cx| {
create_and_open_local_file(&paths::SETTINGS, cx, || { create_and_open_local_file(&paths::SETTINGS, cx, || {
settings::initial_user_settings_content(&assets::Assets) settings::initial_user_settings_content().as_ref().into()
.as_ref()
.into()
}) })
})? })?
.await? .await?

View file

@ -2253,7 +2253,7 @@ impl BufferSnapshot {
} }
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> { pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
self.outline_items_containing(0..self.len(), theme) self.outline_items_containing(0..self.len(), true, theme)
.map(Outline::new) .map(Outline::new)
} }
@ -2265,6 +2265,7 @@ impl BufferSnapshot {
let position = position.to_offset(self); let position = position.to_offset(self);
let mut items = self.outline_items_containing( let mut items = self.outline_items_containing(
position.saturating_sub(1)..self.len().min(position + 1), position.saturating_sub(1)..self.len().min(position + 1),
false,
theme, theme,
)?; )?;
let mut prev_depth = None; let mut prev_depth = None;
@ -2279,6 +2280,7 @@ impl BufferSnapshot {
fn outline_items_containing( fn outline_items_containing(
&self, &self,
range: Range<usize>, range: Range<usize>,
include_extra_context: bool,
theme: Option<&SyntaxTheme>, theme: Option<&SyntaxTheme>,
) -> Option<Vec<OutlineItem<Anchor>>> { ) -> Option<Vec<OutlineItem<Anchor>>> {
let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| { let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
@ -2313,7 +2315,10 @@ impl BufferSnapshot {
let node_is_name; let node_is_name;
if capture.index == config.name_capture_ix { if capture.index == config.name_capture_ix {
node_is_name = true; node_is_name = true;
} else if Some(capture.index) == config.context_capture_ix { } else if Some(capture.index) == config.context_capture_ix
|| (Some(capture.index) == config.extra_context_capture_ix
&& include_extra_context)
{
node_is_name = false; node_is_name = false;
} else { } else {
continue; continue;
@ -2340,10 +2345,12 @@ impl BufferSnapshot {
buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end, buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
true, true,
); );
let mut last_buffer_range_end = 0;
for (buffer_range, is_name) in buffer_ranges { for (buffer_range, is_name) in buffer_ranges {
if !text.is_empty() { if !text.is_empty() && buffer_range.start > last_buffer_range_end {
text.push(' '); text.push(' ');
} }
last_buffer_range_end = buffer_range.end;
if is_name { if is_name {
let mut start = text.len(); let mut start = text.len();
let end = start + buffer_range.len(); let end = start + buffer_range.len();

View file

@ -592,6 +592,52 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui::TestAppContext) {
); );
} }
#[gpui::test]
async fn test_outline_with_extra_context(cx: &mut gpui::TestAppContext) {
let language = javascript_lang()
.with_outline_query(
r#"
(function_declaration
"function" @context
name: (_) @name
parameters: (formal_parameters
"(" @context.extra
")" @context.extra)) @item
"#,
)
.unwrap();
let text = r#"
function a() {}
function b(c) {}
"#
.unindent();
let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(language), cx));
let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
// extra context nodes are included in the outline.
let outline = snapshot.outline(None).unwrap();
assert_eq!(
outline
.items
.iter()
.map(|item| (item.text.as_str(), item.depth))
.collect::<Vec<_>>(),
&[("function a()", 0), ("function b( )", 0),]
);
// extra context nodes do not appear in breadcrumbs.
let symbols = snapshot.symbols_containing(3, None).unwrap();
assert_eq!(
symbols
.iter()
.map(|item| (item.text.as_str(), item.depth))
.collect::<Vec<_>>(),
&[("function a", 0)]
);
}
#[gpui::test] #[gpui::test]
async fn test_symbols_containing(cx: &mut gpui::TestAppContext) { async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
let text = r#" let text = r#"

View file

@ -34,7 +34,7 @@ use std::{
fmt::Debug, fmt::Debug,
hash::Hash, hash::Hash,
mem, mem,
ops::Range, ops::{Not, Range},
path::{Path, PathBuf}, path::{Path, PathBuf},
str, str,
sync::{ sync::{
@ -455,6 +455,7 @@ struct OutlineConfig {
item_capture_ix: u32, item_capture_ix: u32,
name_capture_ix: u32, name_capture_ix: u32,
context_capture_ix: Option<u32>, context_capture_ix: Option<u32>,
extra_context_capture_ix: Option<u32>,
} }
struct InjectionConfig { struct InjectionConfig {
@ -500,6 +501,7 @@ struct AvailableLanguage {
grammar: tree_sitter::Language, grammar: tree_sitter::Language,
lsp_adapters: Vec<Arc<dyn LspAdapter>>, lsp_adapters: Vec<Arc<dyn LspAdapter>>,
get_queries: fn(&str) -> LanguageQueries, get_queries: fn(&str) -> LanguageQueries,
loaded: bool,
} }
pub struct LanguageRegistry { pub struct LanguageRegistry {
@ -527,6 +529,7 @@ struct LanguageRegistryState {
subscription: (watch::Sender<()>, watch::Receiver<()>), subscription: (watch::Sender<()>, watch::Receiver<()>),
theme: Option<Arc<Theme>>, theme: Option<Arc<Theme>>,
version: usize, version: usize,
reload_count: usize,
} }
pub struct PendingLanguageServer { pub struct PendingLanguageServer {
@ -547,6 +550,7 @@ impl LanguageRegistry {
subscription: watch::channel(), subscription: watch::channel(),
theme: Default::default(), theme: Default::default(),
version: 0, version: 0,
reload_count: 0,
}), }),
language_server_download_dir: None, language_server_download_dir: None,
lsp_binary_statuses_tx, lsp_binary_statuses_tx,
@ -566,6 +570,14 @@ impl LanguageRegistry {
self.executor = Some(executor); self.executor = Some(executor);
} }
/// Clear out all of the loaded languages and reload them from scratch.
///
/// This is useful in development, when queries have changed.
#[cfg(debug_assertions)]
pub fn reload(&self) {
self.state.write().reload();
}
pub fn register( pub fn register(
&self, &self,
path: &'static str, path: &'static str,
@ -582,6 +594,7 @@ impl LanguageRegistry {
grammar, grammar,
lsp_adapters, lsp_adapters,
get_queries, get_queries,
loaded: false,
}); });
} }
@ -590,7 +603,7 @@ impl LanguageRegistry {
let mut result = state let mut result = state
.available_languages .available_languages
.iter() .iter()
.map(|l| l.config.name.to_string()) .filter_map(|l| l.loaded.not().then_some(l.config.name.to_string()))
.chain(state.languages.iter().map(|l| l.config.name.to_string())) .chain(state.languages.iter().map(|l| l.config.name.to_string()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
result.sort_unstable_by_key(|language_name| language_name.to_lowercase()); result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
@ -603,6 +616,7 @@ impl LanguageRegistry {
state state
.available_languages .available_languages
.iter() .iter()
.filter(|l| !l.loaded)
.flat_map(|l| l.lsp_adapters.clone()) .flat_map(|l| l.lsp_adapters.clone())
.chain( .chain(
state state
@ -639,10 +653,17 @@ impl LanguageRegistry {
self.state.read().subscription.1.clone() self.state.read().subscription.1.clone()
} }
/// The number of times that the registry has been changed,
/// by adding languages or reloading.
pub fn version(&self) -> usize { pub fn version(&self) -> usize {
self.state.read().version self.state.read().version
} }
/// The number of times that the registry has been reloaded.
pub fn reload_count(&self) -> usize {
self.state.read().reload_count
}
pub fn set_theme(&self, theme: Arc<Theme>) { pub fn set_theme(&self, theme: Arc<Theme>) {
let mut state = self.state.write(); let mut state = self.state.write();
state.theme = Some(theme.clone()); state.theme = Some(theme.clone());
@ -721,7 +742,7 @@ impl LanguageRegistry {
if let Some(language) = state if let Some(language) = state
.available_languages .available_languages
.iter() .iter()
.find(|l| callback(&l.config)) .find(|l| !l.loaded && callback(&l.config))
.cloned() .cloned()
{ {
let txs = state let txs = state
@ -743,9 +764,7 @@ impl LanguageRegistry {
let language = Arc::new(language); let language = Arc::new(language);
let mut state = this.state.write(); let mut state = this.state.write();
state.add(language.clone()); state.add(language.clone());
state state.mark_language_loaded(id);
.available_languages
.retain(|language| language.id != id);
if let Some(mut txs) = state.loading_languages.remove(&id) { if let Some(mut txs) = state.loading_languages.remove(&id) {
for tx in txs.drain(..) { for tx in txs.drain(..) {
let _ = tx.send(Ok(language.clone())); let _ = tx.send(Ok(language.clone()));
@ -753,10 +772,9 @@ impl LanguageRegistry {
} }
} }
Err(err) => { Err(err) => {
log::error!("failed to load language {name} - {err}");
let mut state = this.state.write(); let mut state = this.state.write();
state state.mark_language_loaded(id);
.available_languages
.retain(|language| language.id != id);
if let Some(mut txs) = state.loading_languages.remove(&id) { if let Some(mut txs) = state.loading_languages.remove(&id) {
for tx in txs.drain(..) { for tx in txs.drain(..) {
let _ = tx.send(Err(anyhow!( let _ = tx.send(Err(anyhow!(
@ -905,6 +923,28 @@ impl LanguageRegistryState {
self.version += 1; self.version += 1;
*self.subscription.0.borrow_mut() = (); *self.subscription.0.borrow_mut() = ();
} }
#[cfg(debug_assertions)]
fn reload(&mut self) {
self.languages.clear();
self.version += 1;
self.reload_count += 1;
for language in &mut self.available_languages {
language.loaded = false;
}
*self.subscription.0.borrow_mut() = ();
}
/// Mark the given language a having been loaded, so that the
/// language registry won't try to load it again.
fn mark_language_loaded(&mut self, id: AvailableLanguageId) {
for language in &mut self.available_languages {
if language.id == id {
language.loaded = true;
break;
}
}
}
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@ -1021,34 +1061,22 @@ impl Language {
pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> { pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
if let Some(query) = queries.highlights { if let Some(query) = queries.highlights {
self = self self = self.with_highlights_query(query.as_ref())?;
.with_highlights_query(query.as_ref())
.expect("failed to evaluate highlights query");
} }
if let Some(query) = queries.brackets { if let Some(query) = queries.brackets {
self = self self = self.with_brackets_query(query.as_ref())?;
.with_brackets_query(query.as_ref())
.expect("failed to load brackets query");
} }
if let Some(query) = queries.indents { if let Some(query) = queries.indents {
self = self self = self.with_indents_query(query.as_ref())?;
.with_indents_query(query.as_ref())
.expect("failed to load indents query");
} }
if let Some(query) = queries.outline { if let Some(query) = queries.outline {
self = self self = self.with_outline_query(query.as_ref())?;
.with_outline_query(query.as_ref())
.expect("failed to load outline query");
} }
if let Some(query) = queries.injections { if let Some(query) = queries.injections {
self = self self = self.with_injection_query(query.as_ref())?;
.with_injection_query(query.as_ref())
.expect("failed to load injection query");
} }
if let Some(query) = queries.overrides { if let Some(query) = queries.overrides {
self = self self = self.with_override_query(query.as_ref())?;
.with_override_query(query.as_ref())
.expect("failed to load override query");
} }
Ok(self) Ok(self)
} }
@ -1064,12 +1092,14 @@ impl Language {
let mut item_capture_ix = None; let mut item_capture_ix = None;
let mut name_capture_ix = None; let mut name_capture_ix = None;
let mut context_capture_ix = None; let mut context_capture_ix = None;
let mut extra_context_capture_ix = None;
get_capture_indices( get_capture_indices(
&query, &query,
&mut [ &mut [
("item", &mut item_capture_ix), ("item", &mut item_capture_ix),
("name", &mut name_capture_ix), ("name", &mut name_capture_ix),
("context", &mut context_capture_ix), ("context", &mut context_capture_ix),
("context.extra", &mut extra_context_capture_ix),
], ],
); );
if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) { if let Some((item_capture_ix, name_capture_ix)) = item_capture_ix.zip(name_capture_ix) {
@ -1078,6 +1108,7 @@ impl Language {
item_capture_ix, item_capture_ix,
name_capture_ix, name_capture_ix,
context_capture_ix, context_capture_ix,
extra_context_capture_ix,
}); });
} }
Ok(self) Ok(self)

View file

@ -523,7 +523,7 @@ impl Project {
_subscriptions: vec![ _subscriptions: vec![
cx.observe_global::<SettingsStore, _>(Self::on_settings_changed) cx.observe_global::<SettingsStore, _>(Self::on_settings_changed)
], ],
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx), _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
_maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx), _maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
active_entry: None, active_entry: None,
languages, languages,
@ -592,7 +592,7 @@ impl Project {
active_entry: None, active_entry: None,
collaborators: Default::default(), collaborators: Default::default(),
join_project_response_message_id: response.message_id, join_project_response_message_id: response.message_id,
_maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx), _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
_maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx), _maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
languages, languages,
user_store: user_store.clone(), user_store: user_store.clone(),
@ -2238,13 +2238,34 @@ impl Project {
} }
fn maintain_buffer_languages( fn maintain_buffer_languages(
languages: &LanguageRegistry, languages: Arc<LanguageRegistry>,
cx: &mut ModelContext<Project>, cx: &mut ModelContext<Project>,
) -> Task<()> { ) -> Task<()> {
let mut subscription = languages.subscribe(); let mut subscription = languages.subscribe();
let mut prev_reload_count = languages.reload_count();
cx.spawn_weak(|project, mut cx| async move { cx.spawn_weak(|project, mut cx| async move {
while let Some(()) = subscription.next().await { while let Some(()) = subscription.next().await {
if let Some(project) = project.upgrade(&cx) { if let Some(project) = project.upgrade(&cx) {
// If the language registry has been reloaded, then remove and
// re-assign the languages on all open buffers.
let reload_count = languages.reload_count();
if reload_count > prev_reload_count {
prev_reload_count = reload_count;
project.update(&mut cx, |this, cx| {
let buffers = this
.opened_buffers
.values()
.filter_map(|b| b.upgrade(cx))
.collect::<Vec<_>>();
for buffer in buffers {
if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned() {
this.unregister_buffer_from_language_servers(&buffer, &f, cx);
buffer.update(cx, |buffer, cx| buffer.set_language(None, cx));
}
}
});
}
project.update(&mut cx, |project, cx| { project.update(&mut cx, |project, cx| {
let mut plain_text_buffers = Vec::new(); let mut plain_text_buffers = Vec::new();
let mut buffers_with_unknown_injections = Vec::new(); let mut buffers_with_unknown_injections = Vec::new();

View file

@ -12,7 +12,6 @@ doctest = false
test-support = ["gpui/test-support", "fs/test-support"] test-support = ["gpui/test-support", "fs/test-support"]
[dependencies] [dependencies]
assets = { path = "../assets" }
collections = { path = "../collections" } collections = { path = "../collections" }
gpui = { path = "../gpui" } gpui = { path = "../gpui" }
sqlez = { path = "../sqlez" } sqlez = { path = "../sqlez" }
@ -25,6 +24,7 @@ futures.workspace = true
json_comments = "0.2" json_comments = "0.2"
lazy_static.workspace = true lazy_static.workspace = true
postage.workspace = true postage.workspace = true
rust-embed.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true

View file

@ -1,6 +1,5 @@
use crate::settings_store::parse_json_with_comments; use crate::{settings_store::parse_json_with_comments, SettingsAssets};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use assets::Assets;
use collections::BTreeMap; use collections::BTreeMap;
use gpui::{keymap_matcher::Binding, AppContext}; use gpui::{keymap_matcher::Binding, AppContext};
use schemars::{ use schemars::{
@ -10,11 +9,11 @@ use schemars::{
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::{value::RawValue, Value}; use serde_json::{value::RawValue, Value};
use util::ResultExt; use util::{asset_str, ResultExt};
#[derive(Deserialize, Default, Clone, JsonSchema)] #[derive(Deserialize, Default, Clone, JsonSchema)]
#[serde(transparent)] #[serde(transparent)]
pub struct KeymapFileContent(Vec<KeymapBlock>); pub struct KeymapFile(Vec<KeymapBlock>);
#[derive(Deserialize, Default, Clone, JsonSchema)] #[derive(Deserialize, Default, Clone, JsonSchema)]
pub struct KeymapBlock { pub struct KeymapBlock {
@ -40,11 +39,10 @@ impl JsonSchema for KeymapAction {
#[derive(Deserialize)] #[derive(Deserialize)]
struct ActionWithData(Box<str>, Box<RawValue>); struct ActionWithData(Box<str>, Box<RawValue>);
impl KeymapFileContent { impl KeymapFile {
pub fn load_asset(asset_path: &str, cx: &mut AppContext) -> Result<()> { pub fn load_asset(asset_path: &str, cx: &mut AppContext) -> Result<()> {
let content = Assets::get(asset_path).unwrap().data; let content = asset_str::<SettingsAssets>(asset_path);
let content_str = std::str::from_utf8(content.as_ref()).unwrap(); Self::parse(content.as_ref())?.add_to_cx(cx)
Self::parse(content_str)?.add_to_cx(cx)
} }
pub fn parse(content: &str) -> Result<Self> { pub fn parse(content: &str) -> Result<Self> {
@ -83,40 +81,40 @@ impl KeymapFileContent {
} }
Ok(()) Ok(())
} }
}
pub fn keymap_file_json_schema(action_names: &[&'static str]) -> serde_json::Value { pub fn generate_json_schema(action_names: &[&'static str]) -> serde_json::Value {
let mut root_schema = SchemaSettings::draft07() let mut root_schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false) .with(|settings| settings.option_add_null_type = false)
.into_generator() .into_generator()
.into_root_schema_for::<KeymapFileContent>(); .into_root_schema_for::<KeymapFile>();
let action_schema = Schema::Object(SchemaObject { let action_schema = Schema::Object(SchemaObject {
subschemas: Some(Box::new(SubschemaValidation { subschemas: Some(Box::new(SubschemaValidation {
one_of: Some(vec![ one_of: Some(vec![
Schema::Object(SchemaObject { Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))), instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some( enum_values: Some(
action_names action_names
.iter() .iter()
.map(|name| Value::String(name.to_string())) .map(|name| Value::String(name.to_string()))
.collect(), .collect(),
), ),
..Default::default() ..Default::default()
}), }),
Schema::Object(SchemaObject { Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))), instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
..Default::default() ..Default::default()
}), }),
]), ]),
..Default::default()
})),
..Default::default() ..Default::default()
})), });
..Default::default()
});
root_schema root_schema
.definitions .definitions
.insert("KeymapAction".to_owned(), action_schema); .insert("KeymapAction".to_owned(), action_schema);
serde_json::to_value(root_schema).unwrap() serde_json::to_value(root_schema).unwrap()
}
} }

View file

@ -2,31 +2,37 @@ mod keymap_file;
mod settings_file; mod settings_file;
mod settings_store; mod settings_store;
use gpui::AssetSource; use rust_embed::RustEmbed;
pub use keymap_file::{keymap_file_json_schema, KeymapFileContent}; use std::{borrow::Cow, str};
use util::asset_str;
pub use keymap_file::KeymapFile;
pub use settings_file::*; pub use settings_file::*;
pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore}; pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore};
use std::{borrow::Cow, str};
pub const DEFAULT_SETTINGS_ASSET_PATH: &str = "settings/default.json"; #[derive(RustEmbed)]
const INITIAL_USER_SETTINGS_ASSET_PATH: &str = "settings/initial_user_settings.json"; #[folder = "../../assets"]
const INITIAL_LOCAL_SETTINGS_ASSET_PATH: &str = "settings/initial_local_settings.json"; #[include = "settings/*"]
#[include = "keymaps/*"]
#[exclude = "*.DS_Store"]
pub struct SettingsAssets;
pub fn default_settings() -> Cow<'static, str> { pub fn default_settings() -> Cow<'static, str> {
asset_str(&assets::Assets, DEFAULT_SETTINGS_ASSET_PATH) asset_str::<SettingsAssets>("settings/default.json")
} }
pub fn initial_user_settings_content(assets: &dyn AssetSource) -> Cow<'_, str> { pub fn default_keymap() -> Cow<'static, str> {
asset_str(assets, INITIAL_USER_SETTINGS_ASSET_PATH) asset_str::<SettingsAssets>("keymaps/default.json")
} }
pub fn initial_local_settings_content(assets: &dyn AssetSource) -> Cow<'_, str> { pub fn vim_keymap() -> Cow<'static, str> {
asset_str(assets, INITIAL_LOCAL_SETTINGS_ASSET_PATH) asset_str::<SettingsAssets>("keymaps/vim.json")
} }
fn asset_str<'a>(assets: &'a dyn AssetSource, path: &str) -> Cow<'a, str> { pub fn initial_user_settings_content() -> Cow<'static, str> {
match assets.load(path).unwrap() { asset_str::<SettingsAssets>("settings/initial_user_settings.json")
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()), }
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
} pub fn initial_local_settings_content() -> Cow<'static, str> {
asset_str::<SettingsAssets>("settings/initial_local_settings.json")
} }

View file

@ -1,6 +1,5 @@
use crate::{settings_store::SettingsStore, Setting}; use crate::{settings_store::SettingsStore, Setting};
use anyhow::Result; use anyhow::Result;
use assets::Assets;
use fs::Fs; use fs::Fs;
use futures::{channel::mpsc, StreamExt}; use futures::{channel::mpsc, StreamExt};
use gpui::{executor::Background, AppContext}; use gpui::{executor::Background, AppContext};
@ -111,7 +110,7 @@ async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
Err(err) => { Err(err) => {
if let Some(e) = err.downcast_ref::<std::io::Error>() { if let Some(e) = err.downcast_ref::<std::io::Error>() {
if e.kind() == ErrorKind::NotFound { if e.kind() == ErrorKind::NotFound {
return Ok(crate::initial_user_settings_content(&Assets).to_string()); return Ok(crate::initial_user_settings_content().to_string());
} }
} }
return Err(err); return Err(err);

View file

@ -21,6 +21,7 @@ isahc.workspace = true
smol.workspace = true smol.workspace = true
url = "2.2" url = "2.2"
rand.workspace = true rand.workspace = true
rust-embed.workspace = true
tempdir = { workspace = true, optional = true } tempdir = { workspace = true, optional = true }
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true

View file

@ -7,6 +7,7 @@ pub mod paths;
pub mod test; pub mod test;
use std::{ use std::{
borrow::Cow,
cmp::{self, Ordering}, cmp::{self, Ordering},
ops::{AddAssign, Range, RangeInclusive}, ops::{AddAssign, Range, RangeInclusive},
panic::Location, panic::Location,
@ -284,6 +285,14 @@ impl<T: Rng> Iterator for RandomCharIter<T> {
} }
} }
/// Get an embedded file as a string.
pub fn asset_str<A: rust_embed::RustEmbed>(path: &str) -> Cow<'static, str> {
match A::get(path).unwrap().data {
Cow::Borrowed(bytes) => Cow::Borrowed(std::str::from_utf8(bytes).unwrap()),
Cow::Owned(bytes) => Cow::Owned(String::from_utf8(bytes).unwrap()),
}
}
// copy unstable standard feature option unzip // copy unstable standard feature option unzip
// https://github.com/rust-lang/rust/issues/87800 // https://github.com/rust-lang/rust/issues/87800
// Remove when this ship in Rust 1.66 or 1.67 // Remove when this ship in Rust 1.66 or 1.67

View file

@ -24,7 +24,6 @@ nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", f
tokio = { version = "1.15", "optional" = true } tokio = { version = "1.15", "optional" = true }
serde_json.workspace = true serde_json.workspace = true
assets = { path = "../assets" }
collections = { path = "../collections" } collections = { path = "../collections" }
command_palette = { path = "../command_palette" } command_palette = { path = "../command_palette" }
editor = { path = "../editor" } editor = { path = "../editor" }

View file

@ -27,7 +27,7 @@ impl<'a> VimTestContext<'a> {
cx.update_global(|store: &mut SettingsStore, cx| { cx.update_global(|store: &mut SettingsStore, cx| {
store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(enabled)); store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(enabled));
}); });
settings::KeymapFileContent::load_asset("keymaps/vim.json", cx).unwrap(); settings::KeymapFile::load_asset("keymaps/vim.json", cx).unwrap();
}); });
// Setup search toolbars and keypress hook // Setup search toolbars and keypress hook

View file

@ -19,7 +19,6 @@ test-support = [
] ]
[dependencies] [dependencies]
assets = { path = "../assets" }
db = { path = "../db" } db = { path = "../db" }
call = { path = "../call" } call = { path = "../call" }
client = { path = "../client" } client = { path = "../client" }

View file

@ -17,7 +17,6 @@ path = "src/main.rs"
[dependencies] [dependencies]
activity_indicator = { path = "../activity_indicator" } activity_indicator = { path = "../activity_indicator" }
assets = { path = "../assets" }
auto_update = { path = "../auto_update" } auto_update = { path = "../auto_update" }
breadcrumbs = { path = "../breadcrumbs" } breadcrumbs = { path = "../breadcrumbs" }
call = { path = "../call" } call = { path = "../call" }
@ -107,7 +106,7 @@ tree-sitter = "0.20"
tree-sitter-c = "0.20.1" tree-sitter-c = "0.20.1"
tree-sitter-cpp = "0.20.0" tree-sitter-cpp = "0.20.0"
tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" } tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" }
tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" } tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "4ba9dab6e2602960d95b2b625f3386c27e08084e" }
tree-sitter-embedded-template = "0.20.0" tree-sitter-embedded-template = "0.20.0"
tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" } tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" }
tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" } tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" }

View file

@ -1,3 +1,5 @@
use std::process::Command;
fn main() { fn main() {
println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7"); println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7");
@ -21,4 +23,32 @@ fn main() {
// Register exported Objective-C selectors, protocols, etc // Register exported Objective-C selectors, protocols, etc
println!("cargo:rustc-link-arg=-Wl,-ObjC"); println!("cargo:rustc-link-arg=-Wl,-ObjC");
// Install dependencies for theme-generation
let output = Command::new("npm")
.current_dir("../../styles")
.args(["install", "--no-save"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"failed to install theme dependencies {}",
String::from_utf8_lossy(&output.stderr)
);
}
// Regenerate themes
let output = Command::new("npm")
.current_dir("../../styles")
.args(["run", "build"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"build script failed {}",
String::from_utf8_lossy(&output.stderr)
);
}
println!("cargo:rerun-if-changed=../../styles/src");
} }

View file

@ -4,6 +4,10 @@ use rust_embed::RustEmbed;
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "../../assets"] #[folder = "../../assets"]
#[include = "fonts/**/*"]
#[include = "icons/**/*"]
#[include = "themes/**/*"]
#[include = "*.md"]
#[exclude = "*.DS_Store"] #[exclude = "*.DS_Store"]
pub struct Assets; pub struct Assets;

View file

@ -3,6 +3,7 @@ pub use language::*;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use std::{borrow::Cow, str, sync::Arc}; use std::{borrow::Cow, str, sync::Arc};
use util::asset_str;
mod c; mod c;
mod elixir; mod elixir;
@ -179,10 +180,7 @@ fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
for path in LanguageDir::iter() { for path in LanguageDir::iter() {
if let Some(remainder) = path.strip_prefix(name) { if let Some(remainder) = path.strip_prefix(name) {
if remainder.starts_with(filename_prefix) { if remainder.starts_with(filename_prefix) {
let contents = match LanguageDir::get(path.as_ref()).unwrap().data { let contents = asset_str::<LanguageDir>(path.as_ref());
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
};
match &mut result { match &mut result {
None => result = Some(contents), None => result = Some(contents),
Some(r) => r.to_mut().push_str(contents.as_ref()), Some(r) => r.to_mut().push_str(contents.as_ref()),

View file

@ -1,20 +1,5 @@
["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword ["when" "and" "or" "not" "in" "not in" "fn" "do" "end" "catch" "rescue" "after" "else"] @keyword
(unary_operator
operator: "@" @comment.doc
operand: (call
target: (identifier) @comment.doc.__attribute__
(arguments
[
(string) @comment.doc
(charlist) @comment.doc
(sigil
quoted_start: _ @comment.doc
quoted_end: _ @comment.doc) @comment.doc
(boolean) @comment.doc
]))
(#match? @comment.doc.__attribute__ "^(moduledoc|typedoc|doc)$"))
(unary_operator (unary_operator
operator: "&" operator: "&"
operand: (integer) @operator) operand: (integer) @operator)
@ -84,6 +69,11 @@
quoted_start: _ @string.special quoted_start: _ @string.special
quoted_end: _ @string.special) @string.special quoted_end: _ @string.special) @string.special
(
(identifier) @comment.unused
(#match? @comment.unused "^_")
)
(call (call
target: [ target: [
(identifier) @function (identifier) @function
@ -99,17 +89,12 @@
(binary_operator (binary_operator
left: (identifier) @function left: (identifier) @function
operator: "when") operator: "when")
(binary_operator
operator: "|>"
right: (identifier))
]) ])
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
(call
target: (identifier) @keyword
(arguments
(binary_operator
operator: "|>"
right: (identifier)))
(#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
(binary_operator (binary_operator
operator: "|>" operator: "|>"
right: (identifier) @function) right: (identifier) @function)
@ -127,10 +112,18 @@
(#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$") (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
) )
( (unary_operator
(identifier) @comment.unused operator: "@" @comment.doc
(#match? @comment.unused "^_") operand: (call
) target: (identifier) @__attribute__ @comment.doc
(arguments
[
(string)
(charlist)
(sigil)
(boolean)
] @comment.doc))
(#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
(comment) @comment (comment) @comment

View file

@ -1,6 +1,4 @@
[ (call) @indent
(call)
] @indent
(_ "[" "]" @end) @indent (_ "[" "]" @end) @indent
(_ "{" "}" @end) @indent (_ "{" "}" @end) @indent

View file

@ -8,9 +8,19 @@
(arguments (arguments
[ [
(identifier) @name (identifier) @name
(call target: (identifier) @name) (call
target: (identifier) @name
(arguments
"(" @context.extra
_* @context.extra
")" @context.extra))
(binary_operator (binary_operator
left: (call target: (identifier) @name) left: (call
target: (identifier) @name
(arguments
"(" @context.extra
_* @context.extra
")" @context.extra))
operator: "when") operator: "when")
]) ])
(#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item (#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item

View file

@ -6,7 +6,7 @@ use gpui::AppContext;
use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter}; use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use serde_json::json; use serde_json::json;
use settings::{keymap_file_json_schema, SettingsJsonSchemaParams, SettingsStore}; use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
use smol::fs; use smol::fs;
use staff_mode::StaffMode; use staff_mode::StaffMode;
use std::{ use std::{
@ -143,7 +143,7 @@ impl LspAdapter for JsonLspAdapter {
}, },
{ {
"fileMatch": [schema_file_match(&paths::KEYMAP)], "fileMatch": [schema_file_match(&paths::KEYMAP)],
"schema": keymap_file_json_schema(&action_names), "schema": KeymapFile::generate_json_schema(&action_names),
} }
] ]
} }

View file

@ -14,11 +14,11 @@
(list_marker_parenthesis) (list_marker_parenthesis)
] @punctuation.list_marker ] @punctuation.list_marker
[ (code_span) @text.literal
(indented_code_block)
(fenced_code_block) (fenced_code_block
(code_span) (info_string
] @text.literal (language) @text.literal))
(link_destination) @link_uri (link_destination) @link_uri
(link_text) @link_text (link_text) @link_text

View file

@ -327,10 +327,10 @@ mod tests {
.map(|item| (item.text.as_str(), item.depth)) .map(|item| (item.text.as_str(), item.depth))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
&[ &[
("function a ( )", 0), ("function a()", 0),
("async function a2 ( )", 1), ("async function a2()", 1),
("let b", 0), ("let b", 0),
("function getB ( )", 0), ("function getB()", 0),
("const d", 0), ("const d", 0),
] ]
); );

View file

@ -2,7 +2,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use assets::Assets;
use backtrace::Backtrace; use backtrace::Backtrace;
use cli::{ use cli::{
ipc::{self, IpcSender}, ipc::{self, IpcSender},
@ -58,7 +57,8 @@ use staff_mode::StaffMode;
use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
use workspace::{item::ItemHandle, notifications::NotifyResultExt, AppState, Workspace}; use workspace::{item::ItemHandle, notifications::NotifyResultExt, AppState, Workspace};
use zed::{ use zed::{
self, build_window_options, handle_keymap_file_changes, initialize_workspace, languages, menus, assets::Assets, build_window_options, handle_keymap_file_changes, initialize_workspace,
languages, menus,
}; };
fn main() { fn main() {
@ -160,6 +160,8 @@ fn main() {
ai::init(cx); ai::init(cx);
cx.spawn(|cx| watch_themes(fs.clone(), cx)).detach(); cx.spawn(|cx| watch_themes(fs.clone(), cx)).detach();
cx.spawn(|_| watch_languages(fs.clone(), languages.clone()))
.detach();
languages.set_theme(theme::current(cx).clone()); languages.set_theme(theme::current(cx).clone());
cx.observe_global::<SettingsStore, _>({ cx.observe_global::<SettingsStore, _>({
@ -660,11 +662,30 @@ async fn watch_themes(fs: Arc<dyn Fs>, mut cx: AsyncAppContext) -> Option<()> {
Some(()) Some(())
} }
#[cfg(debug_assertions)]
async fn watch_languages(fs: Arc<dyn Fs>, languages: Arc<LanguageRegistry>) -> Option<()> {
let mut events = fs
.watch(
"crates/zed/src/languages".as_ref(),
Duration::from_millis(100),
)
.await;
while (events.next().await).is_some() {
languages.reload();
}
Some(())
}
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
async fn watch_themes(_fs: Arc<dyn Fs>, _cx: AsyncAppContext) -> Option<()> { async fn watch_themes(_fs: Arc<dyn Fs>, _cx: AsyncAppContext) -> Option<()> {
None None
} }
#[cfg(not(debug_assertions))]
async fn watch_languages(_: Arc<dyn Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
None
}
fn connect_to_cli( fn connect_to_cli(
server_name: &str, server_name: &str,
) -> Result<(mpsc::Receiver<CliRequest>, IpcSender<CliResponse>)> { ) -> Result<(mpsc::Receiver<CliRequest>, IpcSender<CliResponse>)> {

View file

@ -1,7 +1,9 @@
pub mod assets;
pub mod languages; pub mod languages;
pub mod menus; pub mod menus;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub mod test; pub mod test;
use ai::AssistantPanel; use ai::AssistantPanel;
use anyhow::Context; use anyhow::Context;
use assets::Assets; use assets::Assets;
@ -31,12 +33,11 @@ use project_panel::ProjectPanel;
use search::{BufferSearchBar, ProjectSearchBar}; use search::{BufferSearchBar, ProjectSearchBar};
use serde::Deserialize; use serde::Deserialize;
use serde_json::to_string_pretty; use serde_json::to_string_pretty;
use settings::{ use settings::{initial_local_settings_content, KeymapFile, SettingsStore};
initial_local_settings_content, KeymapFileContent, SettingsStore, DEFAULT_SETTINGS_ASSET_PATH,
};
use std::{borrow::Cow, str, sync::Arc}; use std::{borrow::Cow, str, sync::Arc};
use terminal_view::terminal_panel::{self, TerminalPanel}; use terminal_view::terminal_panel::{self, TerminalPanel};
use util::{ use util::{
asset_str,
channel::ReleaseChannel, channel::ReleaseChannel,
paths::{self, LOCAL_SETTINGS_RELATIVE_PATH}, paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
ResultExt, ResultExt,
@ -150,7 +151,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
move |workspace: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext<Workspace>| { move |workspace: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext<Workspace>| {
open_bundled_file( open_bundled_file(
workspace, workspace,
"licenses.md", asset_str::<Assets>("licenses.md"),
"Open Source License Attribution", "Open Source License Attribution",
"Markdown", "Markdown",
cx, cx,
@ -170,9 +171,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
cx.add_action( cx.add_action(
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| { move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
create_and_open_local_file(&paths::SETTINGS, cx, || { create_and_open_local_file(&paths::SETTINGS, cx, || {
settings::initial_user_settings_content(&Assets) settings::initial_user_settings_content().as_ref().into()
.as_ref()
.into()
}) })
.detach_and_log_err(cx); .detach_and_log_err(cx);
}, },
@ -182,7 +181,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
move |workspace: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext<Workspace>| { move |workspace: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext<Workspace>| {
open_bundled_file( open_bundled_file(
workspace, workspace,
"keymaps/default.json", settings::default_keymap(),
"Default Key Bindings", "Default Key Bindings",
"JSON", "JSON",
cx, cx,
@ -195,7 +194,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
cx: &mut ViewContext<Workspace>| { cx: &mut ViewContext<Workspace>| {
open_bundled_file( open_bundled_file(
workspace, workspace,
DEFAULT_SETTINGS_ASSET_PATH, settings::default_settings(),
"Default Settings", "Default Settings",
"JSON", "JSON",
cx, cx,
@ -532,11 +531,11 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
pub fn load_default_keymap(cx: &mut AppContext) { pub fn load_default_keymap(cx: &mut AppContext) {
for path in ["keymaps/default.json", "keymaps/vim.json"] { for path in ["keymaps/default.json", "keymaps/vim.json"] {
KeymapFileContent::load_asset(path, cx).unwrap(); KeymapFile::load_asset(path, cx).unwrap();
} }
if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() { if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() {
KeymapFileContent::load_asset(asset_path, cx).unwrap(); KeymapFile::load_asset(asset_path, cx).unwrap();
} }
} }
@ -547,7 +546,7 @@ pub fn handle_keymap_file_changes(
cx.spawn(move |mut cx| async move { cx.spawn(move |mut cx| async move {
let mut settings_subscription = None; let mut settings_subscription = None;
while let Some(user_keymap_content) = user_keymap_file_rx.next().await { while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
if let Ok(keymap_content) = KeymapFileContent::parse(&user_keymap_content) { if let Ok(keymap_content) = KeymapFile::parse(&user_keymap_content) {
cx.update(|cx| { cx.update(|cx| {
cx.clear_bindings(); cx.clear_bindings();
load_default_keymap(cx); load_default_keymap(cx);
@ -624,11 +623,7 @@ fn open_local_settings_file(
if let Some(buffer) = editor.buffer().read(cx).as_singleton() { if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
if buffer.read(cx).is_empty() { if buffer.read(cx).is_empty() {
buffer.update(cx, |buffer, cx| { buffer.update(cx, |buffer, cx| {
buffer.edit( buffer.edit([(0..0, initial_local_settings_content())], None, cx)
[(0..0, initial_local_settings_content(&Assets))],
None,
cx,
)
}); });
} }
} }
@ -704,7 +699,7 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Works
fn open_bundled_file( fn open_bundled_file(
workspace: &mut Workspace, workspace: &mut Workspace,
asset_path: &'static str, text: Cow<'static, str>,
title: &'static str, title: &'static str,
language: &'static str, language: &'static str,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
@ -716,13 +711,9 @@ fn open_bundled_file(
.update(&mut cx, |workspace, cx| { .update(&mut cx, |workspace, cx| {
workspace.with_local_workspace(cx, |workspace, cx| { workspace.with_local_workspace(cx, |workspace, cx| {
let project = workspace.project(); let project = workspace.project();
let buffer = project.update(cx, |project, cx| { let buffer = project.update(cx, move |project, cx| {
let text = Assets::get(asset_path)
.map(|f| f.data)
.unwrap_or_else(|| Cow::Borrowed(b"File not found"));
let text = str::from_utf8(text.as_ref()).unwrap();
project project
.create_buffer(text, language, cx) .create_buffer(text.as_ref(), language, cx)
.expect("creating buffers on a local workspace always succeeds") .expect("creating buffers on a local workspace always succeeds")
}); });
let buffer = cx.add_model(|cx| { let buffer = cx.add_model(|cx| {

4
rust-toolchain.toml Normal file
View file

@ -0,0 +1,4 @@
[toolchain]
channel = "1.70"
components = [ "rustfmt" ]
targets = [ "x86_64-apple-darwin", "aarch64-apple-darwin", "wasm32-wasi" ]