Merge remote-tracking branch 'origin/main' into room
This commit is contained in:
commit
afaacba41f
92 changed files with 10800 additions and 6586 deletions
|
@ -7,6 +7,7 @@ use std::{borrow::Cow, str, sync::Arc};
|
|||
mod c;
|
||||
mod elixir;
|
||||
mod go;
|
||||
mod html;
|
||||
mod installation;
|
||||
mod json;
|
||||
mod language_plugin;
|
||||
|
@ -46,6 +47,11 @@ pub async fn init(languages: Arc<LanguageRegistry>, _executor: Arc<Background>)
|
|||
tree_sitter_cpp::language(),
|
||||
Some(CachedLspAdapter::new(c::CLspAdapter).await),
|
||||
),
|
||||
(
|
||||
"css",
|
||||
tree_sitter_css::language(),
|
||||
None, //
|
||||
),
|
||||
(
|
||||
"elixir",
|
||||
tree_sitter_elixir::language(),
|
||||
|
@ -96,8 +102,13 @@ pub async fn init(languages: Arc<LanguageRegistry>, _executor: Arc<Background>)
|
|||
tree_sitter_typescript::language_tsx(),
|
||||
Some(CachedLspAdapter::new(typescript::TypeScriptLspAdapter).await),
|
||||
),
|
||||
(
|
||||
"html",
|
||||
tree_sitter_html::language(),
|
||||
Some(CachedLspAdapter::new(html::HtmlLspAdapter).await),
|
||||
),
|
||||
] {
|
||||
languages.add(Arc::new(language(name, grammar, lsp_adapter)));
|
||||
languages.add(language(name, grammar, lsp_adapter));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +116,7 @@ pub(crate) fn language(
|
|||
name: &str,
|
||||
grammar: tree_sitter::Language,
|
||||
lsp_adapter: Option<Arc<CachedLspAdapter>>,
|
||||
) -> Language {
|
||||
) -> Arc<Language> {
|
||||
let config = toml::from_slice(
|
||||
&LanguageDir::get(&format!("{}/config.toml", name))
|
||||
.unwrap()
|
||||
|
@ -142,7 +153,7 @@ pub(crate) fn language(
|
|||
if let Some(lsp_adapter) = lsp_adapter {
|
||||
language = language.with_lsp_adapter(lsp_adapter)
|
||||
}
|
||||
language
|
||||
Arc::new(language)
|
||||
}
|
||||
|
||||
fn load_query(name: &str, filename_prefix: &str) -> Option<Cow<'static, str>> {
|
||||
|
|
|
@ -112,7 +112,7 @@ impl super::LspAdapter for CLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
completion: &lsp::CompletionItem,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let label = completion
|
||||
.label
|
||||
|
@ -190,7 +190,7 @@ impl super::LspAdapter for CLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
|
||||
|
@ -251,7 +251,6 @@ mod tests {
|
|||
use gpui::MutableAppContext;
|
||||
use language::{AutoindentMode, Buffer};
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_c_autoindent(cx: &mut MutableAppContext) {
|
||||
|
@ -262,7 +261,7 @@ mod tests {
|
|||
let language = crate::languages::language("c", tree_sitter_c::language(), None);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
|
||||
|
||||
// empty function
|
||||
buffer.edit([(0..0, "int main() {}")], None, cx);
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
(identifier) @variable
|
||||
|
||||
((identifier) @constant
|
||||
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
|
||||
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||
|
||||
(call_expression
|
||||
function: (identifier) @function)
|
||||
|
|
|
@ -37,11 +37,11 @@
|
|||
(type_identifier) @type
|
||||
|
||||
((identifier) @constant
|
||||
(#match? @constant "^[A-Z][A-Z\\d_]*$"))
|
||||
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||
|
||||
(field_identifier) @property
|
||||
(statement_identifier) @label
|
||||
(this) @variable.builtin
|
||||
(this) @variable.special
|
||||
|
||||
[
|
||||
"break"
|
||||
|
|
3
crates/zed/src/languages/css/brackets.scm
Normal file
3
crates/zed/src/languages/css/brackets.scm
Normal file
|
@ -0,0 +1,3 @@
|
|||
("(" @open ")" @close)
|
||||
("[" @open "]" @close)
|
||||
("{" @open "}" @close)
|
9
crates/zed/src/languages/css/config.toml
Normal file
9
crates/zed/src/languages/css/config.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name = "CSS"
|
||||
path_suffixes = ["css"]
|
||||
autoclose_before = ";:.,=}])>"
|
||||
brackets = [
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
{ start = "[", end = "]", close = true, newline = true },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = false }
|
||||
]
|
78
crates/zed/src/languages/css/highlights.scm
Normal file
78
crates/zed/src/languages/css/highlights.scm
Normal file
|
@ -0,0 +1,78 @@
|
|||
(comment) @comment
|
||||
|
||||
[
|
||||
(tag_name)
|
||||
(nesting_selector)
|
||||
(universal_selector)
|
||||
] @tag
|
||||
|
||||
[
|
||||
"~"
|
||||
">"
|
||||
"+"
|
||||
"-"
|
||||
"*"
|
||||
"/"
|
||||
"="
|
||||
"^="
|
||||
"|="
|
||||
"~="
|
||||
"$="
|
||||
"*="
|
||||
"and"
|
||||
"or"
|
||||
"not"
|
||||
"only"
|
||||
] @operator
|
||||
|
||||
(attribute_selector (plain_value) @string)
|
||||
|
||||
(attribute_name) @attribute
|
||||
(pseudo_element_selector (tag_name) @attribute)
|
||||
(pseudo_class_selector (class_name) @attribute)
|
||||
|
||||
[
|
||||
(class_name)
|
||||
(id_name)
|
||||
(namespace_name)
|
||||
(property_name)
|
||||
(feature_name)
|
||||
] @property
|
||||
|
||||
(function_name) @function
|
||||
|
||||
(
|
||||
[
|
||||
(property_name)
|
||||
(plain_value)
|
||||
] @variable.special
|
||||
(#match? @variable.special "^--")
|
||||
)
|
||||
|
||||
[
|
||||
"@media"
|
||||
"@import"
|
||||
"@charset"
|
||||
"@namespace"
|
||||
"@supports"
|
||||
"@keyframes"
|
||||
(at_keyword)
|
||||
(to)
|
||||
(from)
|
||||
(important)
|
||||
] @keyword
|
||||
|
||||
(string_value) @string
|
||||
(color_value) @string.special
|
||||
|
||||
[
|
||||
(integer_value)
|
||||
(float_value)
|
||||
] @number
|
||||
|
||||
(unit) @type
|
||||
|
||||
[
|
||||
","
|
||||
":"
|
||||
] @punctuation.delimiter
|
1
crates/zed/src/languages/css/indents.scm
Normal file
1
crates/zed/src/languages/css/indents.scm
Normal file
|
@ -0,0 +1 @@
|
|||
(_ "{" "}" @end) @indent
|
|
@ -113,7 +113,7 @@ impl LspAdapter for ElixirLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
completion: &lsp::CompletionItem,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
match completion.kind.zip(completion.detail.as_ref()) {
|
||||
Some((_, detail)) if detail.starts_with("(function)") => {
|
||||
|
@ -168,7 +168,7 @@ impl LspAdapter for ElixirLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: SymbolKind,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
SymbolKind::METHOD | SymbolKind::FUNCTION => {
|
||||
|
|
|
@ -134,7 +134,7 @@ impl super::LspAdapter for GoLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
completion: &lsp::CompletionItem,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let label = &completion.label;
|
||||
|
||||
|
@ -235,7 +235,7 @@ impl super::LspAdapter for GoLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
|
||||
|
|
101
crates/zed/src/languages/html.rs
Normal file
101
crates/zed/src/languages/html.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use super::installation::{npm_install_packages, npm_package_latest_version};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use client::http::HttpClient;
|
||||
use futures::StreamExt;
|
||||
use language::{LanguageServerName, LspAdapter};
|
||||
use serde_json::json;
|
||||
use smol::fs;
|
||||
use std::{any::Any, path::PathBuf, sync::Arc};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct HtmlLspAdapter;
|
||||
|
||||
impl HtmlLspAdapter {
|
||||
const BIN_PATH: &'static str =
|
||||
"node_modules/vscode-langservers-extracted/bin/vscode-html-language-server";
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl LspAdapter for HtmlLspAdapter {
|
||||
async fn name(&self) -> LanguageServerName {
|
||||
LanguageServerName("vscode-html-language-server".into())
|
||||
}
|
||||
|
||||
async fn server_args(&self) -> Vec<String> {
|
||||
vec!["--stdio".into()]
|
||||
}
|
||||
|
||||
async fn fetch_latest_server_version(
|
||||
&self,
|
||||
_: Arc<dyn HttpClient>,
|
||||
) -> Result<Box<dyn 'static + Any + Send>> {
|
||||
Ok(Box::new(npm_package_latest_version("vscode-langservers-extracted").await?) as Box<_>)
|
||||
}
|
||||
|
||||
async fn fetch_server_binary(
|
||||
&self,
|
||||
version: Box<dyn 'static + Send + Any>,
|
||||
_: Arc<dyn HttpClient>,
|
||||
container_dir: PathBuf,
|
||||
) -> Result<PathBuf> {
|
||||
let version = version.downcast::<String>().unwrap();
|
||||
let version_dir = container_dir.join(version.as_str());
|
||||
fs::create_dir_all(&version_dir)
|
||||
.await
|
||||
.context("failed to create version directory")?;
|
||||
let binary_path = version_dir.join(Self::BIN_PATH);
|
||||
|
||||
if fs::metadata(&binary_path).await.is_err() {
|
||||
npm_install_packages(
|
||||
[("vscode-langservers-extracted", version.as_str())],
|
||||
&version_dir,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(mut entries) = fs::read_dir(&container_dir).await.log_err() {
|
||||
while let Some(entry) = entries.next().await {
|
||||
if let Some(entry) = entry.log_err() {
|
||||
let entry_path = entry.path();
|
||||
if entry_path.as_path() != version_dir {
|
||||
fs::remove_dir_all(&entry_path).await.log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(binary_path)
|
||||
}
|
||||
|
||||
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
|
||||
(|| async move {
|
||||
let mut last_version_dir = None;
|
||||
let mut entries = fs::read_dir(&container_dir).await?;
|
||||
while let Some(entry) = entries.next().await {
|
||||
let entry = entry?;
|
||||
if entry.file_type().await?.is_dir() {
|
||||
last_version_dir = Some(entry.path());
|
||||
}
|
||||
}
|
||||
let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
|
||||
let bin_path = last_version_dir.join(Self::BIN_PATH);
|
||||
if bin_path.exists() {
|
||||
Ok(bin_path)
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"missing executable in directory {:?}",
|
||||
last_version_dir
|
||||
))
|
||||
}
|
||||
})()
|
||||
.await
|
||||
.log_err()
|
||||
}
|
||||
|
||||
async fn initialization_options(&self) -> Option<serde_json::Value> {
|
||||
Some(json!({
|
||||
"provideFormatter": true
|
||||
}))
|
||||
}
|
||||
}
|
2
crates/zed/src/languages/html/brackets.scm
Normal file
2
crates/zed/src/languages/html/brackets.scm
Normal file
|
@ -0,0 +1,2 @@
|
|||
("<" @open ">" @close)
|
||||
("\"" @open "\"" @close)
|
12
crates/zed/src/languages/html/config.toml
Normal file
12
crates/zed/src/languages/html/config.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "HTML"
|
||||
path_suffixes = ["html"]
|
||||
autoclose_before = ">})"
|
||||
brackets = [
|
||||
{ start = "<", end = ">", close = true, newline = true },
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = false },
|
||||
{ start = "!--", end = " --", close = true, newline = false },
|
||||
]
|
||||
|
||||
block_comment = ["<!-- ", " -->"]
|
15
crates/zed/src/languages/html/highlights.scm
Normal file
15
crates/zed/src/languages/html/highlights.scm
Normal file
|
@ -0,0 +1,15 @@
|
|||
(tag_name) @keyword
|
||||
(erroneous_end_tag_name) @keyword
|
||||
(doctype) @constant
|
||||
(attribute_name) @property
|
||||
(attribute_value) @string
|
||||
(comment) @comment
|
||||
|
||||
"=" @operator
|
||||
|
||||
[
|
||||
"<"
|
||||
">"
|
||||
"</"
|
||||
"/>"
|
||||
] @punctuation.bracket
|
6
crates/zed/src/languages/html/indents.scm
Normal file
6
crates/zed/src/languages/html/indents.scm
Normal file
|
@ -0,0 +1,6 @@
|
|||
(start_tag ">" @end) @indent
|
||||
(self_closing_tag "/>" @end) @indent
|
||||
|
||||
(element
|
||||
(start_tag) @start
|
||||
(end_tag)? @end) @indent
|
7
crates/zed/src/languages/html/injections.scm
Normal file
7
crates/zed/src/languages/html/injections.scm
Normal file
|
@ -0,0 +1,7 @@
|
|||
(script_element
|
||||
(raw_text) @content
|
||||
(#set! "language" "javascript"))
|
||||
|
||||
(style_element
|
||||
(raw_text) @content
|
||||
(#set! "language" "css"))
|
0
crates/zed/src/languages/html/outline.scm
Normal file
0
crates/zed/src/languages/html/outline.scm
Normal file
|
@ -51,12 +51,12 @@
|
|||
(shorthand_property_identifier)
|
||||
(shorthand_property_identifier_pattern)
|
||||
] @constant
|
||||
(#match? @constant "^[A-Z_][A-Z\\d_]+$"))
|
||||
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
||||
|
||||
; Literals
|
||||
|
||||
(this) @variable.builtin
|
||||
(super) @variable.builtin
|
||||
(this) @variable.special
|
||||
(super) @variable.special
|
||||
|
||||
[
|
||||
(true)
|
||||
|
|
|
@ -90,7 +90,7 @@ impl LspAdapter for PythonLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
item: &lsp::CompletionItem,
|
||||
language: &language::Language,
|
||||
language: &Arc<language::Language>,
|
||||
) -> Option<language::CodeLabel> {
|
||||
let label = &item.label;
|
||||
let grammar = language.grammar()?;
|
||||
|
@ -112,7 +112,7 @@ impl LspAdapter for PythonLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
language: &language::Language,
|
||||
language: &Arc<language::Language>,
|
||||
) -> Option<language::CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
|
||||
|
@ -149,7 +149,6 @@ mod tests {
|
|||
use gpui::{ModelContext, MutableAppContext};
|
||||
use language::{AutoindentMode, Buffer};
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_python_autoindent(cx: &mut MutableAppContext) {
|
||||
|
@ -160,7 +159,7 @@ mod tests {
|
|||
cx.set_global(settings);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
|
||||
let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
|
||||
let ix = buffer.len();
|
||||
buffer.edit([(ix..ix, text)], Some(AutoindentMode::EachLine), cx);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
(#match? @type "^[A-Z]"))
|
||||
|
||||
((identifier) @constant
|
||||
(#match? @constant "^[A-Z][A-Z_]*$"))
|
||||
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||
|
||||
; Builtin functions
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ impl LspAdapter for RustLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
completion: &lsp::CompletionItem,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
match completion.kind {
|
||||
Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => {
|
||||
|
@ -196,7 +196,7 @@ impl LspAdapter for RustLspAdapter {
|
|||
&self,
|
||||
name: &str,
|
||||
kind: lsp::SymbolKind,
|
||||
language: &Language,
|
||||
language: &Arc<Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => {
|
||||
|
@ -439,7 +439,7 @@ mod tests {
|
|||
cx.set_global(settings);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(language, cx);
|
||||
|
||||
// indent between braces
|
||||
buffer.set_text("fn a() {}", cx);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(type_identifier) @type
|
||||
(primitive_type) @type.builtin
|
||||
(self) @variable.builtin
|
||||
(self) @variable.special
|
||||
(field_identifier) @property
|
||||
|
||||
(call_expression
|
||||
|
@ -27,22 +27,13 @@
|
|||
|
||||
; Identifier conventions
|
||||
|
||||
; Assume uppercase names are enum constructors
|
||||
((identifier) @variant
|
||||
(#match? @variant "^[A-Z]"))
|
||||
|
||||
; Assume that uppercase names in paths are types
|
||||
((scoped_identifier
|
||||
path: (identifier) @type)
|
||||
(#match? @type "^[A-Z]"))
|
||||
((scoped_identifier
|
||||
path: (scoped_identifier
|
||||
name: (identifier) @type))
|
||||
; Assume uppercase names are types/enum-constructors
|
||||
((identifier) @type
|
||||
(#match? @type "^[A-Z]"))
|
||||
|
||||
; Assume all-caps names are constants
|
||||
((identifier) @constant
|
||||
(#match? @constant "^[A-Z][A-Z\\d_]+$"))
|
||||
(#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
|
||||
|
||||
[
|
||||
"("
|
||||
|
|
|
@ -115,7 +115,7 @@ impl LspAdapter for TypeScriptLspAdapter {
|
|||
async fn label_for_completion(
|
||||
&self,
|
||||
item: &lsp::CompletionItem,
|
||||
language: &language::Language,
|
||||
language: &Arc<language::Language>,
|
||||
) -> Option<language::CodeLabel> {
|
||||
use lsp::CompletionItemKind as Kind;
|
||||
let len = item.label.len();
|
||||
|
@ -144,7 +144,6 @@ impl LspAdapter for TypeScriptLspAdapter {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::MutableAppContext;
|
||||
use unindent::Unindent;
|
||||
|
@ -172,9 +171,8 @@ mod tests {
|
|||
"#
|
||||
.unindent();
|
||||
|
||||
let buffer = cx.add_model(|cx| {
|
||||
language::Buffer::new(0, text, cx).with_language(Arc::new(language), cx)
|
||||
});
|
||||
let buffer =
|
||||
cx.add_model(|cx| language::Buffer::new(0, text, cx).with_language(language, cx));
|
||||
let outline = buffer.read(cx).snapshot().outline(None).unwrap();
|
||||
assert_eq!(
|
||||
outline
|
||||
|
|
|
@ -51,12 +51,12 @@
|
|||
(shorthand_property_identifier)
|
||||
(shorthand_property_identifier_pattern)
|
||||
] @constant
|
||||
(#match? @constant "^[A-Z_][A-Z\\d_]+$"))
|
||||
(#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
|
||||
|
||||
; Literals
|
||||
|
||||
(this) @variable.builtin
|
||||
(super) @variable.builtin
|
||||
(this) @variable.special
|
||||
(super) @variable.special
|
||||
|
||||
[
|
||||
(true)
|
||||
|
|
|
@ -20,7 +20,7 @@ use futures::{
|
|||
FutureExt, SinkExt, StreamExt,
|
||||
};
|
||||
use gpui::{executor::Background, App, AssetSource, AsyncAppContext, Task, ViewContext};
|
||||
use isahc::{config::Configurable, AsyncBody, Request};
|
||||
use isahc::{config::Configurable, Request};
|
||||
use language::LanguageRegistry;
|
||||
use log::LevelFilter;
|
||||
use parking_lot::Mutex;
|
||||
|
@ -88,7 +88,7 @@ fn main() {
|
|||
});
|
||||
|
||||
app.run(move |cx| {
|
||||
let client = client::Client::new(http.clone());
|
||||
let client = client::Client::new(http.clone(), cx);
|
||||
let mut languages = LanguageRegistry::new(login_shell_env_loaded);
|
||||
languages.set_language_server_download_dir(zed::paths::LANGUAGES_DIR.clone());
|
||||
let languages = Arc::new(languages);
|
||||
|
@ -120,7 +120,6 @@ fn main() {
|
|||
vim::init(cx);
|
||||
terminal::init(cx);
|
||||
|
||||
let db = cx.background().block(db);
|
||||
cx.spawn(|cx| watch_themes(fs.clone(), themes.clone(), cx))
|
||||
.detach();
|
||||
|
||||
|
@ -139,6 +138,10 @@ fn main() {
|
|||
.detach();
|
||||
|
||||
let project_store = cx.add_model(|_| ProjectStore::new());
|
||||
let db = cx.background().block(db);
|
||||
client.start_telemetry(db.clone());
|
||||
client.report_event("start app", Default::default());
|
||||
|
||||
let app_state = Arc::new(AppState {
|
||||
languages,
|
||||
themes,
|
||||
|
@ -280,12 +283,10 @@ fn init_panic_hook(app_version: String, http: Arc<dyn HttpClient>, background: A
|
|||
"token": ZED_SECRET_CLIENT_TOKEN,
|
||||
}))
|
||||
.unwrap();
|
||||
let request = Request::builder()
|
||||
.uri(&panic_report_url)
|
||||
.method(http::Method::POST)
|
||||
let request = Request::post(&panic_report_url)
|
||||
.redirect_policy(isahc::config::RedirectPolicy::Follow)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(AsyncBody::from(body))?;
|
||||
.body(body.into())?;
|
||||
let response = http.send(request).await.context("error sending panic")?;
|
||||
if response.status().is_success() {
|
||||
fs::remove_file(child_path)
|
||||
|
|
|
@ -328,6 +328,11 @@ pub fn menus() -> Vec<Menu<'static>> {
|
|||
action: Box::new(command_palette::Toggle),
|
||||
},
|
||||
MenuItem::Separator,
|
||||
MenuItem::Action {
|
||||
name: "View Telemetry Log",
|
||||
action: Box::new(crate::OpenTelemetryLog),
|
||||
},
|
||||
MenuItem::Separator,
|
||||
MenuItem::Action {
|
||||
name: "Documentation",
|
||||
action: Box::new(crate::OpenBrowser {
|
||||
|
|
|
@ -55,6 +55,7 @@ actions!(
|
|||
DebugElements,
|
||||
OpenSettings,
|
||||
OpenLog,
|
||||
OpenTelemetryLog,
|
||||
OpenKeymap,
|
||||
OpenDefaultSettings,
|
||||
OpenDefaultKeymap,
|
||||
|
@ -145,6 +146,12 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||
open_log_file(workspace, app_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |workspace: &mut Workspace, _: &OpenTelemetryLog, cx: &mut ViewContext<Workspace>| {
|
||||
open_telemetry_log_file(workspace, app_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
||||
|
@ -485,6 +492,62 @@ fn open_log_file(
|
|||
});
|
||||
}
|
||||
|
||||
fn open_telemetry_log_file(
|
||||
workspace: &mut Workspace,
|
||||
app_state: Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
workspace.with_local_workspace(cx, app_state.clone(), |_, cx| {
|
||||
cx.spawn_weak(|workspace, mut cx| async move {
|
||||
let workspace = workspace.upgrade(&cx)?;
|
||||
let path = app_state.client.telemetry_log_file_path()?;
|
||||
let log = app_state.fs.load(&path).await.log_err()?;
|
||||
|
||||
const MAX_TELEMETRY_LOG_LEN: usize = 5 * 1024 * 1024;
|
||||
let mut start_offset = log.len().saturating_sub(MAX_TELEMETRY_LOG_LEN);
|
||||
if let Some(newline_offset) = log[start_offset..].find('\n') {
|
||||
start_offset += newline_offset + 1;
|
||||
}
|
||||
let log_suffix = &log[start_offset..];
|
||||
|
||||
workspace.update(&mut cx, |workspace, cx| {
|
||||
let project = workspace.project().clone();
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
||||
.expect("creating buffers on a local workspace always succeeds");
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.set_language(app_state.languages.get_language("JSON"), cx);
|
||||
buffer.edit(
|
||||
[(
|
||||
0..0,
|
||||
concat!(
|
||||
"// Zed collects anonymous usage data to help us understand how people are using the app.\n",
|
||||
"// After the beta release, we'll provide the ability to opt out of this telemetry.\n",
|
||||
"// Here is the data that has been reported for the current session:\n",
|
||||
"\n"
|
||||
),
|
||||
)],
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
buffer.edit([(buffer.len()..buffer.len(), log_suffix)], None, cx);
|
||||
});
|
||||
|
||||
let buffer = cx.add_model(|cx| {
|
||||
MultiBuffer::singleton(buffer, cx).with_title("Telemetry Log".into())
|
||||
});
|
||||
workspace.add_item(
|
||||
Box::new(cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
Some(())
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
}
|
||||
|
||||
fn open_bundled_config_file(
|
||||
workspace: &mut Workspace,
|
||||
app_state: Arc<AppState>,
|
||||
|
@ -1051,7 +1114,7 @@ mod tests {
|
|||
assert!(!editor.is_dirty(cx));
|
||||
assert_eq!(editor.title(cx), "untitled");
|
||||
assert!(Arc::ptr_eq(
|
||||
editor.language_at(0, cx).unwrap(),
|
||||
&editor.language_at(0, cx).unwrap(),
|
||||
&languages::PLAIN_TEXT
|
||||
));
|
||||
editor.handle_input("hi", cx);
|
||||
|
@ -1138,7 +1201,7 @@ mod tests {
|
|||
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert!(Arc::ptr_eq(
|
||||
editor.language_at(0, cx).unwrap(),
|
||||
&editor.language_at(0, cx).unwrap(),
|
||||
&languages::PLAIN_TEXT
|
||||
));
|
||||
editor.handle_input("hi", cx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue