logiguard fork v3: full patch set on verified 8c74db0 tree
Includes prior-session patches (carry forward so the app compiles): - crates/gpui/build.rs: cross-compile manifest fix - crates/gpui/src/platform.rs: PlatformWindow::activate_with_token trait method - crates/gpui/src/window.rs: Window::activate_with_token public API - crates/gpui_linux/src/linux/wayland/window.rs: WaylandWindow::activate_with_token + activate() keyboard-serial fix Plus the focus-serial fix: - serial.rs: SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; latest_serial_of() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
16
extensions/test-extension/Cargo.toml
Normal file
16
extensions/test-extension/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "zed_test_extension"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "Apache-2.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/test_extension.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
zed_extension_api = { path = "../../crates/extension_api" }
|
||||
1
extensions/test-extension/LICENSE-APACHE
Symbolic link
1
extensions/test-extension/LICENSE-APACHE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-APACHE
|
||||
5
extensions/test-extension/README.md
Normal file
5
extensions/test-extension/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Test Extension
|
||||
|
||||
This is a test extension that we use in the tests for the `extension` crate.
|
||||
|
||||
Originally based off the Gleam extension.
|
||||
25
extensions/test-extension/extension.toml
Normal file
25
extensions/test-extension/extension.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
id = "test-extension"
|
||||
name = "Test Extension"
|
||||
description = "An extension for use in tests."
|
||||
version = "0.1.0"
|
||||
schema_version = 1
|
||||
authors = ["Marshall Bowers <elliott.codes@gmail.com>"]
|
||||
repository = "https://github.com/zed-industries/zed"
|
||||
|
||||
[language_servers.gleam]
|
||||
name = "Gleam LSP"
|
||||
language = "Gleam"
|
||||
|
||||
[grammars.gleam]
|
||||
repository = "https://github.com/gleam-lang/tree-sitter-gleam"
|
||||
commit = "8432ffe32ccd360534837256747beb5b1c82fca1"
|
||||
|
||||
[[capabilities]]
|
||||
kind = "process:exec"
|
||||
command = "echo"
|
||||
args = ["hello from a child process!"]
|
||||
|
||||
[[capabilities]]
|
||||
kind = "process:exec"
|
||||
command = "cmd"
|
||||
args = ["/C", "echo", "hello from a child process!"]
|
||||
12
extensions/test-extension/languages/gleam/config.toml
Normal file
12
extensions/test-extension/languages/gleam/config.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
name = "Gleam"
|
||||
grammar = "gleam"
|
||||
path_suffixes = ["gleam"]
|
||||
line_comments = ["// ", "/// "]
|
||||
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, not_in = ["string", "comment"] },
|
||||
]
|
||||
tab_size = 2
|
||||
162
extensions/test-extension/languages/gleam/highlights.scm
Normal file
162
extensions/test-extension/languages/gleam/highlights.scm
Normal file
@@ -0,0 +1,162 @@
|
||||
; Comments
|
||||
(module_comment) @comment
|
||||
|
||||
(statement_comment) @comment
|
||||
|
||||
(comment) @comment
|
||||
|
||||
; Constants
|
||||
(constant
|
||||
name: (identifier) @constant)
|
||||
|
||||
; Variables
|
||||
(identifier) @variable
|
||||
|
||||
(discard) @comment.unused
|
||||
|
||||
; Modules
|
||||
(module) @module
|
||||
|
||||
(import
|
||||
alias: (identifier) @module)
|
||||
|
||||
(remote_type_identifier
|
||||
module: (identifier) @module)
|
||||
|
||||
(remote_constructor_name
|
||||
module: (identifier) @module)
|
||||
|
||||
((field_access
|
||||
record: (identifier) @module
|
||||
field: (label) @function)
|
||||
(#is-not? local))
|
||||
|
||||
; Functions
|
||||
(unqualified_import
|
||||
(identifier) @function)
|
||||
|
||||
(unqualified_import
|
||||
"type"
|
||||
(type_identifier) @type)
|
||||
|
||||
(unqualified_import
|
||||
(type_identifier) @constructor)
|
||||
|
||||
(function
|
||||
name: (identifier) @function)
|
||||
|
||||
(external_function
|
||||
name: (identifier) @function)
|
||||
|
||||
(function_parameter
|
||||
name: (identifier) @variable.parameter)
|
||||
|
||||
((function_call
|
||||
function: (identifier) @function)
|
||||
(#is-not? local))
|
||||
|
||||
((binary_expression
|
||||
operator: "|>"
|
||||
right: (identifier) @function)
|
||||
(#is-not? local))
|
||||
|
||||
; "Properties"
|
||||
; Assumed to be intended to refer to a name for a field; something that comes
|
||||
; before ":" or after "."
|
||||
; e.g. record field names, tuple indices, names for named arguments, etc
|
||||
(label) @property
|
||||
|
||||
(tuple_access
|
||||
index: (integer) @property)
|
||||
|
||||
; Attributes
|
||||
(attribute
|
||||
"@" @attribute
|
||||
name: (identifier) @attribute)
|
||||
|
||||
(attribute_value
|
||||
(identifier) @constant)
|
||||
|
||||
; Type names
|
||||
(remote_type_identifier) @type
|
||||
|
||||
(type_identifier) @type
|
||||
|
||||
; Data constructors
|
||||
(constructor_name) @constructor
|
||||
|
||||
; Literals
|
||||
(string) @string
|
||||
|
||||
((escape_sequence) @warning
|
||||
; Deprecated in v0.33.0-rc2:
|
||||
(#eq? @warning "\\e"))
|
||||
|
||||
(escape_sequence) @string.escape
|
||||
|
||||
(bit_string_segment_option) @function.builtin
|
||||
|
||||
(integer) @number
|
||||
|
||||
(float) @number
|
||||
|
||||
; Reserved identifiers
|
||||
; TODO: when tree-sitter supports `#any-of?` in the Rust bindings,
|
||||
; refactor this to use `#any-of?` rather than `#match?`
|
||||
((identifier) @warning
|
||||
(#match? @warning "^(auto|delegate|derive|else|implement|macro|test|echo)$"))
|
||||
|
||||
; Keywords
|
||||
[
|
||||
(visibility_modifier) ; "pub"
|
||||
(opacity_modifier) ; "opaque"
|
||||
"as"
|
||||
"assert"
|
||||
"case"
|
||||
"const"
|
||||
; DEPRECATED: 'external' was removed in v0.30.
|
||||
"external"
|
||||
"fn"
|
||||
"if"
|
||||
"import"
|
||||
"let"
|
||||
"panic"
|
||||
"todo"
|
||||
"type"
|
||||
"use"
|
||||
] @keyword
|
||||
|
||||
; Operators
|
||||
(binary_expression
|
||||
operator: _ @operator)
|
||||
|
||||
(boolean_negation
|
||||
"!" @operator)
|
||||
|
||||
(integer_negation
|
||||
"-" @operator)
|
||||
|
||||
; Punctuation
|
||||
[
|
||||
"("
|
||||
")"
|
||||
"["
|
||||
"]"
|
||||
"{"
|
||||
"}"
|
||||
"<<"
|
||||
">>"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"."
|
||||
","
|
||||
; Controversial -- maybe some are operators?
|
||||
":"
|
||||
"#"
|
||||
"="
|
||||
"->"
|
||||
".."
|
||||
"-"
|
||||
"<-"
|
||||
] @punctuation.delimiter
|
||||
11
extensions/test-extension/languages/gleam/indents.scm
Normal file
11
extensions/test-extension/languages/gleam/indents.scm
Normal file
@@ -0,0 +1,11 @@
|
||||
(_
|
||||
"["
|
||||
"]" @end) @indent
|
||||
|
||||
(_
|
||||
"{"
|
||||
"}" @end) @indent
|
||||
|
||||
(_
|
||||
"("
|
||||
")" @end) @indent
|
||||
31
extensions/test-extension/languages/gleam/outline.scm
Normal file
31
extensions/test-extension/languages/gleam/outline.scm
Normal file
@@ -0,0 +1,31 @@
|
||||
(external_type
|
||||
(visibility_modifier)? @context
|
||||
"type" @context
|
||||
(type_name) @name) @item
|
||||
|
||||
(type_definition
|
||||
(visibility_modifier)? @context
|
||||
(opacity_modifier)? @context
|
||||
"type" @context
|
||||
(type_name) @name) @item
|
||||
|
||||
(data_constructor
|
||||
(constructor_name) @name) @item
|
||||
|
||||
(data_constructor_argument
|
||||
(label) @name) @item
|
||||
|
||||
(type_alias
|
||||
(visibility_modifier)? @context
|
||||
"type" @context
|
||||
(type_name) @name) @item
|
||||
|
||||
(function
|
||||
(visibility_modifier)? @context
|
||||
"fn" @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(constant
|
||||
(visibility_modifier)? @context
|
||||
"const" @context
|
||||
name: (_) @name) @item
|
||||
209
extensions/test-extension/src/test_extension.rs
Normal file
209
extensions/test-extension/src/test_extension.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
use std::fs;
|
||||
use zed::lsp::CompletionKind;
|
||||
use zed::{CodeLabel, CodeLabelSpan, LanguageServerId};
|
||||
use zed_extension_api::process::Command;
|
||||
use zed_extension_api::{self as zed, Result};
|
||||
|
||||
struct TestExtension {
|
||||
cached_binary_path: Option<String>,
|
||||
}
|
||||
|
||||
impl TestExtension {
|
||||
fn language_server_binary_path(
|
||||
&mut self,
|
||||
language_server_id: &LanguageServerId,
|
||||
_worktree: &zed::Worktree,
|
||||
) -> Result<String> {
|
||||
let (platform, arch) = zed::current_platform();
|
||||
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
println!("current_dir: {}", current_dir.display());
|
||||
assert_eq!(
|
||||
current_dir.file_name().unwrap().to_str().unwrap(),
|
||||
"test-extension"
|
||||
);
|
||||
|
||||
fs::create_dir_all(current_dir.join("dir-created-with-abs-path")).unwrap();
|
||||
fs::create_dir_all("./dir-created-with-rel-path").unwrap();
|
||||
fs::write("file-created-with-rel-path", b"contents 1").unwrap();
|
||||
fs::write(
|
||||
current_dir.join("file-created-with-abs-path"),
|
||||
b"contents 2",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
fs::read("file-created-with-rel-path").unwrap(),
|
||||
b"contents 1"
|
||||
);
|
||||
assert_eq!(
|
||||
fs::read("file-created-with-abs-path").unwrap(),
|
||||
b"contents 2"
|
||||
);
|
||||
|
||||
let command = match platform {
|
||||
zed::Os::Linux | zed::Os::Mac => Command::new("echo"),
|
||||
zed::Os::Windows => Command::new("cmd").args(["/C", "echo"]),
|
||||
};
|
||||
let output = command.arg("hello from a child process!").output()?;
|
||||
println!(
|
||||
"command output: {}",
|
||||
String::from_utf8_lossy(&output.stdout).trim()
|
||||
);
|
||||
|
||||
if let Some(path) = &self.cached_binary_path
|
||||
&& fs::metadata(path).is_ok_and(|stat| stat.is_file())
|
||||
{
|
||||
return Ok(path.clone());
|
||||
}
|
||||
|
||||
zed::set_language_server_installation_status(
|
||||
language_server_id,
|
||||
&zed::LanguageServerInstallationStatus::CheckingForUpdate,
|
||||
);
|
||||
let release = zed::latest_github_release(
|
||||
"gleam-lang/gleam",
|
||||
zed::GithubReleaseOptions {
|
||||
require_assets: true,
|
||||
pre_release: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
let ext = "tar.gz";
|
||||
let download_type = zed::DownloadedFileType::GzipTar;
|
||||
|
||||
// Do this if you want to actually run this extension -
|
||||
// the actual asset is a .zip. But the integration test is simpler
|
||||
// if every platform uses .tar.gz.
|
||||
//
|
||||
// ext = "zip";
|
||||
// download_type = zed::DownloadedFileType::Zip;
|
||||
|
||||
let asset_name = format!(
|
||||
"gleam-{version}-{arch}-{os}.{ext}",
|
||||
version = release.version,
|
||||
arch = match arch {
|
||||
zed::Architecture::Aarch64 => "aarch64",
|
||||
zed::Architecture::X86 => "x86",
|
||||
zed::Architecture::X8664 => "x86_64",
|
||||
},
|
||||
os = match platform {
|
||||
zed::Os::Mac => "apple-darwin",
|
||||
zed::Os::Linux => "unknown-linux-musl",
|
||||
zed::Os::Windows => "pc-windows-msvc",
|
||||
},
|
||||
);
|
||||
|
||||
let asset = release
|
||||
.assets
|
||||
.iter()
|
||||
.find(|asset| asset.name == asset_name)
|
||||
.ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
|
||||
|
||||
let version_dir = format!("gleam-{}", release.version);
|
||||
let binary_path = format!("{version_dir}/gleam");
|
||||
|
||||
if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) {
|
||||
zed::set_language_server_installation_status(
|
||||
language_server_id,
|
||||
&zed::LanguageServerInstallationStatus::Downloading,
|
||||
);
|
||||
|
||||
zed::download_file(&asset.download_url, &version_dir, download_type)
|
||||
.map_err(|e| format!("failed to download file: {e}"))?;
|
||||
|
||||
zed::set_language_server_installation_status(
|
||||
language_server_id,
|
||||
&zed::LanguageServerInstallationStatus::None,
|
||||
);
|
||||
|
||||
let entries =
|
||||
fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
|
||||
for entry in entries {
|
||||
let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
|
||||
let filename = entry.file_name();
|
||||
let filename = filename.to_str().unwrap();
|
||||
if filename.starts_with("gleam-") && filename != version_dir {
|
||||
fs::remove_dir_all(entry.path()).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.cached_binary_path = Some(binary_path.clone());
|
||||
Ok(binary_path)
|
||||
}
|
||||
}
|
||||
|
||||
impl zed::Extension for TestExtension {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
cached_binary_path: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn language_server_command(
|
||||
&mut self,
|
||||
language_server_id: &LanguageServerId,
|
||||
worktree: &zed::Worktree,
|
||||
) -> Result<zed::Command> {
|
||||
Ok(zed::Command {
|
||||
command: self.language_server_binary_path(language_server_id, worktree)?,
|
||||
args: vec!["lsp".to_string()],
|
||||
env: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn label_for_completion(
|
||||
&self,
|
||||
_language_server_id: &LanguageServerId,
|
||||
completion: zed::lsp::Completion,
|
||||
) -> Option<zed::CodeLabel> {
|
||||
let name = &completion.label;
|
||||
let ty = strip_newlines_from_detail(&completion.detail?);
|
||||
let let_binding = "let a";
|
||||
let colon = ": ";
|
||||
let assignment = " = ";
|
||||
let call = match completion.kind? {
|
||||
CompletionKind::Function | CompletionKind::Constructor => "()",
|
||||
_ => "",
|
||||
};
|
||||
let code = format!("{let_binding}{colon}{ty}{assignment}{name}{call}");
|
||||
|
||||
Some(CodeLabel {
|
||||
spans: vec![
|
||||
CodeLabelSpan::code_range({
|
||||
let start = let_binding.len() + colon.len() + ty.len() + assignment.len();
|
||||
start..start + name.len()
|
||||
}),
|
||||
CodeLabelSpan::code_range({
|
||||
let start = let_binding.len();
|
||||
start..start + colon.len()
|
||||
}),
|
||||
CodeLabelSpan::code_range({
|
||||
let start = let_binding.len() + colon.len();
|
||||
start..start + ty.len()
|
||||
}),
|
||||
],
|
||||
filter_range: (0..name.len()).into(),
|
||||
code,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
zed::register_extension!(TestExtension);
|
||||
|
||||
/// Removes newlines from the completion detail.
|
||||
///
|
||||
/// The Gleam LSP can return types containing newlines, which causes formatting
|
||||
/// issues within the Zed completions menu.
|
||||
fn strip_newlines_from_detail(detail: &str) -> String {
|
||||
let without_newlines = detail
|
||||
.replace("->\n ", "-> ")
|
||||
.replace("\n ", "")
|
||||
.replace(",\n", "");
|
||||
|
||||
let comma_delimited_parts = without_newlines.split(',');
|
||||
comma_delimited_parts
|
||||
.map(|part| part.trim())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
}
|
||||
Reference in New Issue
Block a user