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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,6 @@ path = "src/ai.rs"
doctest = false
[dependencies]
assets = { path = "../assets"}
collections = { path = "../collections"}
editor = { path = "../editor" }
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
[dependencies]
assets = { path = "../assets" }
copilot = { path = "../copilot" }
editor = { path = "../editor" }
fs = { path = "../fs" }

View file

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

View file

@ -2253,7 +2253,7 @@ impl BufferSnapshot {
}
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)
}
@ -2265,6 +2265,7 @@ impl BufferSnapshot {
let position = position.to_offset(self);
let mut items = self.outline_items_containing(
position.saturating_sub(1)..self.len().min(position + 1),
false,
theme,
)?;
let mut prev_depth = None;
@ -2279,6 +2280,7 @@ impl BufferSnapshot {
fn outline_items_containing(
&self,
range: Range<usize>,
include_extra_context: bool,
theme: Option<&SyntaxTheme>,
) -> Option<Vec<OutlineItem<Anchor>>> {
let mut matches = self.syntax.matches(range.clone(), &self.text, |grammar| {
@ -2313,7 +2315,10 @@ impl BufferSnapshot {
let node_is_name;
if capture.index == config.name_capture_ix {
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;
} else {
continue;
@ -2340,10 +2345,12 @@ impl BufferSnapshot {
buffer_ranges.first().unwrap().0.start..buffer_ranges.last().unwrap().0.end,
true,
);
let mut last_buffer_range_end = 0;
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(' ');
}
last_buffer_range_end = buffer_range.end;
if is_name {
let mut start = text.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]
async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
let text = r#"

View file

@ -34,7 +34,7 @@ use std::{
fmt::Debug,
hash::Hash,
mem,
ops::Range,
ops::{Not, Range},
path::{Path, PathBuf},
str,
sync::{
@ -455,6 +455,7 @@ struct OutlineConfig {
item_capture_ix: u32,
name_capture_ix: u32,
context_capture_ix: Option<u32>,
extra_context_capture_ix: Option<u32>,
}
struct InjectionConfig {
@ -500,6 +501,7 @@ struct AvailableLanguage {
grammar: tree_sitter::Language,
lsp_adapters: Vec<Arc<dyn LspAdapter>>,
get_queries: fn(&str) -> LanguageQueries,
loaded: bool,
}
pub struct LanguageRegistry {
@ -527,6 +529,7 @@ struct LanguageRegistryState {
subscription: (watch::Sender<()>, watch::Receiver<()>),
theme: Option<Arc<Theme>>,
version: usize,
reload_count: usize,
}
pub struct PendingLanguageServer {
@ -547,6 +550,7 @@ impl LanguageRegistry {
subscription: watch::channel(),
theme: Default::default(),
version: 0,
reload_count: 0,
}),
language_server_download_dir: None,
lsp_binary_statuses_tx,
@ -566,6 +570,14 @@ impl LanguageRegistry {
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(
&self,
path: &'static str,
@ -582,6 +594,7 @@ impl LanguageRegistry {
grammar,
lsp_adapters,
get_queries,
loaded: false,
});
}
@ -590,7 +603,7 @@ impl LanguageRegistry {
let mut result = state
.available_languages
.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()))
.collect::<Vec<_>>();
result.sort_unstable_by_key(|language_name| language_name.to_lowercase());
@ -603,6 +616,7 @@ impl LanguageRegistry {
state
.available_languages
.iter()
.filter(|l| !l.loaded)
.flat_map(|l| l.lsp_adapters.clone())
.chain(
state
@ -639,10 +653,17 @@ impl LanguageRegistry {
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 {
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>) {
let mut state = self.state.write();
state.theme = Some(theme.clone());
@ -721,7 +742,7 @@ impl LanguageRegistry {
if let Some(language) = state
.available_languages
.iter()
.find(|l| callback(&l.config))
.find(|l| !l.loaded && callback(&l.config))
.cloned()
{
let txs = state
@ -743,9 +764,7 @@ impl LanguageRegistry {
let language = Arc::new(language);
let mut state = this.state.write();
state.add(language.clone());
state
.available_languages
.retain(|language| language.id != id);
state.mark_language_loaded(id);
if let Some(mut txs) = state.loading_languages.remove(&id) {
for tx in txs.drain(..) {
let _ = tx.send(Ok(language.clone()));
@ -753,10 +772,9 @@ impl LanguageRegistry {
}
}
Err(err) => {
log::error!("failed to load language {name} - {err}");
let mut state = this.state.write();
state
.available_languages
.retain(|language| language.id != id);
state.mark_language_loaded(id);
if let Some(mut txs) = state.loading_languages.remove(&id) {
for tx in txs.drain(..) {
let _ = tx.send(Err(anyhow!(
@ -905,6 +923,28 @@ impl LanguageRegistryState {
self.version += 1;
*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"))]
@ -1021,34 +1061,22 @@ impl Language {
pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
if let Some(query) = queries.highlights {
self = self
.with_highlights_query(query.as_ref())
.expect("failed to evaluate highlights query");
self = self.with_highlights_query(query.as_ref())?;
}
if let Some(query) = queries.brackets {
self = self
.with_brackets_query(query.as_ref())
.expect("failed to load brackets query");
self = self.with_brackets_query(query.as_ref())?;
}
if let Some(query) = queries.indents {
self = self
.with_indents_query(query.as_ref())
.expect("failed to load indents query");
self = self.with_indents_query(query.as_ref())?;
}
if let Some(query) = queries.outline {
self = self
.with_outline_query(query.as_ref())
.expect("failed to load outline query");
self = self.with_outline_query(query.as_ref())?;
}
if let Some(query) = queries.injections {
self = self
.with_injection_query(query.as_ref())
.expect("failed to load injection query");
self = self.with_injection_query(query.as_ref())?;
}
if let Some(query) = queries.overrides {
self = self
.with_override_query(query.as_ref())
.expect("failed to load override query");
self = self.with_override_query(query.as_ref())?;
}
Ok(self)
}
@ -1064,12 +1092,14 @@ impl Language {
let mut item_capture_ix = None;
let mut name_capture_ix = None;
let mut context_capture_ix = None;
let mut extra_context_capture_ix = None;
get_capture_indices(
&query,
&mut [
("item", &mut item_capture_ix),
("name", &mut name_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) {
@ -1078,6 +1108,7 @@ impl Language {
item_capture_ix,
name_capture_ix,
context_capture_ix,
extra_context_capture_ix,
});
}
Ok(self)

View file

@ -523,7 +523,7 @@ impl Project {
_subscriptions: vec![
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),
active_entry: None,
languages,
@ -592,7 +592,7 @@ impl Project {
active_entry: None,
collaborators: Default::default(),
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),
languages,
user_store: user_store.clone(),
@ -2238,13 +2238,34 @@ impl Project {
}
fn maintain_buffer_languages(
languages: &LanguageRegistry,
languages: Arc<LanguageRegistry>,
cx: &mut ModelContext<Project>,
) -> Task<()> {
let mut subscription = languages.subscribe();
let mut prev_reload_count = languages.reload_count();
cx.spawn_weak(|project, mut cx| async move {
while let Some(()) = subscription.next().await {
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| {
let mut plain_text_buffers = 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"]
[dependencies]
assets = { path = "../assets" }
collections = { path = "../collections" }
gpui = { path = "../gpui" }
sqlez = { path = "../sqlez" }
@ -25,6 +24,7 @@ futures.workspace = true
json_comments = "0.2"
lazy_static.workspace = true
postage.workspace = true
rust-embed.workspace = true
schemars.workspace = true
serde.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 assets::Assets;
use collections::BTreeMap;
use gpui::{keymap_matcher::Binding, AppContext};
use schemars::{
@ -10,11 +9,11 @@ use schemars::{
};
use serde::Deserialize;
use serde_json::{value::RawValue, Value};
use util::ResultExt;
use util::{asset_str, ResultExt};
#[derive(Deserialize, Default, Clone, JsonSchema)]
#[serde(transparent)]
pub struct KeymapFileContent(Vec<KeymapBlock>);
pub struct KeymapFile(Vec<KeymapBlock>);
#[derive(Deserialize, Default, Clone, JsonSchema)]
pub struct KeymapBlock {
@ -40,11 +39,10 @@ impl JsonSchema for KeymapAction {
#[derive(Deserialize)]
struct ActionWithData(Box<str>, Box<RawValue>);
impl KeymapFileContent {
impl KeymapFile {
pub fn load_asset(asset_path: &str, cx: &mut AppContext) -> Result<()> {
let content = Assets::get(asset_path).unwrap().data;
let content_str = std::str::from_utf8(content.as_ref()).unwrap();
Self::parse(content_str)?.add_to_cx(cx)
let content = asset_str::<SettingsAssets>(asset_path);
Self::parse(content.as_ref())?.add_to_cx(cx)
}
pub fn parse(content: &str) -> Result<Self> {
@ -83,40 +81,40 @@ impl KeymapFileContent {
}
Ok(())
}
}
pub fn keymap_file_json_schema(action_names: &[&'static str]) -> serde_json::Value {
let mut root_schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false)
.into_generator()
.into_root_schema_for::<KeymapFileContent>();
pub fn generate_json_schema(action_names: &[&'static str]) -> serde_json::Value {
let mut root_schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false)
.into_generator()
.into_root_schema_for::<KeymapFile>();
let action_schema = Schema::Object(SchemaObject {
subschemas: Some(Box::new(SubschemaValidation {
one_of: Some(vec![
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some(
action_names
.iter()
.map(|name| Value::String(name.to_string()))
.collect(),
),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
..Default::default()
}),
]),
let action_schema = Schema::Object(SchemaObject {
subschemas: Some(Box::new(SubschemaValidation {
one_of: Some(vec![
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some(
action_names
.iter()
.map(|name| Value::String(name.to_string()))
.collect(),
),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
..Default::default()
}),
]),
..Default::default()
})),
..Default::default()
})),
..Default::default()
});
});
root_schema
.definitions
.insert("KeymapAction".to_owned(), action_schema);
root_schema
.definitions
.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_store;
use gpui::AssetSource;
pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
use rust_embed::RustEmbed;
use std::{borrow::Cow, str};
use util::asset_str;
pub use keymap_file::KeymapFile;
pub use settings_file::*;
pub use settings_store::{Setting, SettingsJsonSchemaParams, SettingsStore};
use std::{borrow::Cow, str};
pub const DEFAULT_SETTINGS_ASSET_PATH: &str = "settings/default.json";
const INITIAL_USER_SETTINGS_ASSET_PATH: &str = "settings/initial_user_settings.json";
const INITIAL_LOCAL_SETTINGS_ASSET_PATH: &str = "settings/initial_local_settings.json";
#[derive(RustEmbed)]
#[folder = "../../assets"]
#[include = "settings/*"]
#[include = "keymaps/*"]
#[exclude = "*.DS_Store"]
pub struct SettingsAssets;
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> {
asset_str(assets, INITIAL_USER_SETTINGS_ASSET_PATH)
pub fn default_keymap() -> Cow<'static, str> {
asset_str::<SettingsAssets>("keymaps/default.json")
}
pub fn initial_local_settings_content(assets: &dyn AssetSource) -> Cow<'_, str> {
asset_str(assets, INITIAL_LOCAL_SETTINGS_ASSET_PATH)
pub fn vim_keymap() -> Cow<'static, str> {
asset_str::<SettingsAssets>("keymaps/vim.json")
}
fn asset_str<'a>(assets: &'a dyn AssetSource, path: &str) -> Cow<'a, str> {
match assets.load(path).unwrap() {
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
}
pub fn initial_user_settings_content() -> Cow<'static, str> {
asset_str::<SettingsAssets>("settings/initial_user_settings.json")
}
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 anyhow::Result;
use assets::Assets;
use fs::Fs;
use futures::{channel::mpsc, StreamExt};
use gpui::{executor::Background, AppContext};
@ -111,7 +110,7 @@ async fn load_settings(fs: &Arc<dyn Fs>) -> Result<String> {
Err(err) => {
if let Some(e) = err.downcast_ref::<std::io::Error>() {
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);

View file

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

View file

@ -7,6 +7,7 @@ pub mod paths;
pub mod test;
use std::{
borrow::Cow,
cmp::{self, Ordering},
ops::{AddAssign, Range, RangeInclusive},
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
// https://github.com/rust-lang/rust/issues/87800
// 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 }
serde_json.workspace = true
assets = { path = "../assets" }
collections = { path = "../collections" }
command_palette = { path = "../command_palette" }
editor = { path = "../editor" }

View file

@ -27,7 +27,7 @@ impl<'a> VimTestContext<'a> {
cx.update_global(|store: &mut SettingsStore, cx| {
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

View file

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

View file

@ -17,7 +17,6 @@ path = "src/main.rs"
[dependencies]
activity_indicator = { path = "../activity_indicator" }
assets = { path = "../assets" }
auto_update = { path = "../auto_update" }
breadcrumbs = { path = "../breadcrumbs" }
call = { path = "../call" }
@ -107,7 +106,7 @@ tree-sitter = "0.20"
tree-sitter-c = "0.20.1"
tree-sitter-cpp = "0.20.0"
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-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" }

View file

@ -1,3 +1,5 @@
use std::process::Command;
fn main() {
println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.15.7");
@ -21,4 +23,32 @@ fn main() {
// Register exported Objective-C selectors, protocols, etc
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)]
#[folder = "../../assets"]
#[include = "fonts/**/*"]
#[include = "icons/**/*"]
#[include = "themes/**/*"]
#[include = "*.md"]
#[exclude = "*.DS_Store"]
pub struct Assets;

View file

@ -3,6 +3,7 @@ pub use language::*;
use node_runtime::NodeRuntime;
use rust_embed::RustEmbed;
use std::{borrow::Cow, str, sync::Arc};
use util::asset_str;
mod c;
mod elixir;
@ -179,10 +180,7 @@ fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
for path in LanguageDir::iter() {
if let Some(remainder) = path.strip_prefix(name) {
if remainder.starts_with(filename_prefix) {
let contents = match LanguageDir::get(path.as_ref()).unwrap().data {
Cow::Borrowed(s) => Cow::Borrowed(str::from_utf8(s).unwrap()),
Cow::Owned(s) => Cow::Owned(String::from_utf8(s).unwrap()),
};
let contents = asset_str::<LanguageDir>(path.as_ref());
match &mut result {
None => result = Some(contents),
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
(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
operator: "&"
operand: (integer) @operator)
@ -84,6 +69,11 @@
quoted_start: _ @string.special
quoted_end: _ @string.special) @string.special
(
(identifier) @comment.unused
(#match? @comment.unused "^_")
)
(call
target: [
(identifier) @function
@ -99,17 +89,12 @@
(binary_operator
left: (identifier) @function
operator: "when")
(binary_operator
operator: "|>"
right: (identifier))
])
(#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
operator: "|>"
right: (identifier) @function)
@ -127,10 +112,18 @@
(#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
)
(
(identifier) @comment.unused
(#match? @comment.unused "^_")
)
(unary_operator
operator: "@" @comment.doc
operand: (call
target: (identifier) @__attribute__ @comment.doc
(arguments
[
(string)
(charlist)
(sigil)
(boolean)
] @comment.doc))
(#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
(comment) @comment

View file

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

View file

@ -8,9 +8,19 @@
(arguments
[
(identifier) @name
(call target: (identifier) @name)
(call
target: (identifier) @name
(arguments
"(" @context.extra
_* @context.extra
")" @context.extra))
(binary_operator
left: (call target: (identifier) @name)
left: (call
target: (identifier) @name
(arguments
"(" @context.extra
_* @context.extra
")" @context.extra))
operator: "when")
])
(#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 node_runtime::NodeRuntime;
use serde_json::json;
use settings::{keymap_file_json_schema, SettingsJsonSchemaParams, SettingsStore};
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
use smol::fs;
use staff_mode::StaffMode;
use std::{
@ -143,7 +143,7 @@ impl LspAdapter for JsonLspAdapter {
},
{
"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)
] @punctuation.list_marker
[
(indented_code_block)
(fenced_code_block)
(code_span)
] @text.literal
(code_span) @text.literal
(fenced_code_block
(info_string
(language) @text.literal))
(link_destination) @link_uri
(link_text) @link_text

View file

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

View file

@ -2,7 +2,6 @@
#![allow(non_snake_case)]
use anyhow::{anyhow, Context, Result};
use assets::Assets;
use backtrace::Backtrace;
use cli::{
ipc::{self, IpcSender},
@ -58,7 +57,8 @@ use staff_mode::StaffMode;
use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt};
use workspace::{item::ItemHandle, notifications::NotifyResultExt, AppState, Workspace};
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() {
@ -160,6 +160,8 @@ fn main() {
ai::init(cx);
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());
cx.observe_global::<SettingsStore, _>({
@ -660,11 +662,30 @@ async fn watch_themes(fs: Arc<dyn Fs>, mut cx: AsyncAppContext) -> Option<()> {
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))]
async fn watch_themes(_fs: Arc<dyn Fs>, _cx: AsyncAppContext) -> Option<()> {
None
}
#[cfg(not(debug_assertions))]
async fn watch_languages(_: Arc<dyn Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
None
}
fn connect_to_cli(
server_name: &str,
) -> Result<(mpsc::Receiver<CliRequest>, IpcSender<CliResponse>)> {

View file

@ -1,7 +1,9 @@
pub mod assets;
pub mod languages;
pub mod menus;
#[cfg(any(test, feature = "test-support"))]
pub mod test;
use ai::AssistantPanel;
use anyhow::Context;
use assets::Assets;
@ -31,12 +33,11 @@ use project_panel::ProjectPanel;
use search::{BufferSearchBar, ProjectSearchBar};
use serde::Deserialize;
use serde_json::to_string_pretty;
use settings::{
initial_local_settings_content, KeymapFileContent, SettingsStore, DEFAULT_SETTINGS_ASSET_PATH,
};
use settings::{initial_local_settings_content, KeymapFile, SettingsStore};
use std::{borrow::Cow, str, sync::Arc};
use terminal_view::terminal_panel::{self, TerminalPanel};
use util::{
asset_str,
channel::ReleaseChannel,
paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
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>| {
open_bundled_file(
workspace,
"licenses.md",
asset_str::<Assets>("licenses.md"),
"Open Source License Attribution",
"Markdown",
cx,
@ -170,9 +171,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
cx.add_action(
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
create_and_open_local_file(&paths::SETTINGS, cx, || {
settings::initial_user_settings_content(&Assets)
.as_ref()
.into()
settings::initial_user_settings_content().as_ref().into()
})
.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>| {
open_bundled_file(
workspace,
"keymaps/default.json",
settings::default_keymap(),
"Default Key Bindings",
"JSON",
cx,
@ -195,7 +194,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
cx: &mut ViewContext<Workspace>| {
open_bundled_file(
workspace,
DEFAULT_SETTINGS_ASSET_PATH,
settings::default_settings(),
"Default Settings",
"JSON",
cx,
@ -532,11 +531,11 @@ fn open_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
pub fn load_default_keymap(cx: &mut AppContext) {
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() {
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 {
let mut settings_subscription = None;
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.clear_bindings();
load_default_keymap(cx);
@ -624,11 +623,7 @@ fn open_local_settings_file(
if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
if buffer.read(cx).is_empty() {
buffer.update(cx, |buffer, cx| {
buffer.edit(
[(0..0, initial_local_settings_content(&Assets))],
None,
cx,
)
buffer.edit([(0..0, initial_local_settings_content())], None, cx)
});
}
}
@ -704,7 +699,7 @@ fn open_telemetry_log_file(workspace: &mut Workspace, cx: &mut ViewContext<Works
fn open_bundled_file(
workspace: &mut Workspace,
asset_path: &'static str,
text: Cow<'static, str>,
title: &'static str,
language: &'static str,
cx: &mut ViewContext<Workspace>,
@ -716,13 +711,9 @@ fn open_bundled_file(
.update(&mut cx, |workspace, cx| {
workspace.with_local_workspace(cx, |workspace, cx| {
let project = workspace.project();
let buffer = project.update(cx, |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();
let buffer = project.update(cx, move |project, cx| {
project
.create_buffer(text, language, cx)
.create_buffer(text.as_ref(), language, cx)
.expect("creating buffers on a local workspace always succeeds")
});
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" ]