Merge branch 'main' into kvark-linux
This commit is contained in:
commit
67555ee5b4
238 changed files with 6624 additions and 3524 deletions
|
@ -2,7 +2,7 @@
|
|||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.122.0"
|
||||
version = "0.123.0"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
|
@ -16,98 +16,99 @@ name = "Zed"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
activity_indicator = { path = "../activity_indicator" }
|
||||
ai = { path = "../ai" }
|
||||
activity_indicator.workspace = true
|
||||
ai.workspace = true
|
||||
anyhow.workspace = true
|
||||
assets = { path = "../assets" }
|
||||
assistant = { path = "../assistant" }
|
||||
assets.workspace = true
|
||||
assistant.workspace = true
|
||||
async-compression.workspace = true
|
||||
async-recursion = "0.3"
|
||||
async-tar = "0.4.2"
|
||||
async-trait.workspace = true
|
||||
audio = { path = "../audio" }
|
||||
auto_update = { path = "../auto_update" }
|
||||
audio.workspace = true
|
||||
auto_update.workspace = true
|
||||
backtrace = "0.3"
|
||||
breadcrumbs = { path = "../breadcrumbs" }
|
||||
call = { path = "../call" }
|
||||
channel = { path = "../channel" }
|
||||
breadcrumbs.workspace = true
|
||||
call.workspace = true
|
||||
channel.workspace = true
|
||||
chrono = "0.4"
|
||||
cli = { path = "../cli" }
|
||||
client = { path = "../client" }
|
||||
collab_ui = { path = "../collab_ui" }
|
||||
collections = { path = "../collections" }
|
||||
command_palette = { path = "../command_palette" }
|
||||
copilot = { path = "../copilot" }
|
||||
copilot_ui = { path = "../copilot_ui" }
|
||||
cli.workspace = true
|
||||
client.workspace = true
|
||||
collab_ui.workspace = true
|
||||
collections.workspace = true
|
||||
command_palette.workspace = true
|
||||
copilot.workspace = true
|
||||
copilot_ui.workspace = true
|
||||
ctor.workspace = true
|
||||
db = { path = "../db" }
|
||||
diagnostics = { path = "../diagnostics" }
|
||||
editor = { path = "../editor" }
|
||||
db.workspace = true
|
||||
diagnostics.workspace = true
|
||||
editor.workspace = true
|
||||
env_logger.workspace = true
|
||||
feature_flags = { path = "../feature_flags" }
|
||||
feedback = { path = "../feedback" }
|
||||
file_finder = { path = "../file_finder" }
|
||||
fs = { path = "../fs" }
|
||||
fsevent = { path = "../fsevent" }
|
||||
feature_flags.workspace = true
|
||||
feedback.workspace = true
|
||||
file_finder.workspace = true
|
||||
fs.workspace = true
|
||||
fsevent.workspace = true
|
||||
futures.workspace = true
|
||||
go_to_line = { path = "../go_to_line" }
|
||||
gpui = { path = "../gpui" }
|
||||
go_to_line.workspace = true
|
||||
gpui.workspace = true
|
||||
ignore = "0.4"
|
||||
image = "0.23"
|
||||
indexmap = "1.6.2"
|
||||
install_cli = { path = "../install_cli" }
|
||||
install_cli.workspace = true
|
||||
isahc.workspace = true
|
||||
itertools = "0.11"
|
||||
journal = { path = "../journal" }
|
||||
language = { path = "../language" }
|
||||
language_selector = { path = "../language_selector" }
|
||||
language_tools = { path = "../language_tools" }
|
||||
journal.workspace = true
|
||||
language.workspace = true
|
||||
language_selector.workspace = true
|
||||
language_tools.workspace = true
|
||||
lazy_static.workspace = true
|
||||
libc = "0.2"
|
||||
log.workspace = true
|
||||
lsp = { path = "../lsp" }
|
||||
markdown_preview = { path = "../markdown_preview" }
|
||||
menu = { path = "../menu" }
|
||||
lsp.workspace = true
|
||||
markdown_preview.workspace = true
|
||||
menu.workspace = true
|
||||
mimalloc = "0.1"
|
||||
node_runtime = { path = "../node_runtime" }
|
||||
notifications = { path = "../notifications" }
|
||||
node_runtime.workspace = true
|
||||
notifications.workspace = true
|
||||
num_cpus = "1.13.0"
|
||||
outline = { path = "../outline" }
|
||||
outline.workspace = true
|
||||
parking_lot.workspace = true
|
||||
postage.workspace = true
|
||||
project = { path = "../project" }
|
||||
project_panel = { path = "../project_panel" }
|
||||
project_symbols = { path = "../project_symbols" }
|
||||
quick_action_bar = { path = "../quick_action_bar" }
|
||||
project.workspace = true
|
||||
project_panel.workspace = true
|
||||
project_symbols.workspace = true
|
||||
quick_action_bar.workspace = true
|
||||
rand.workspace = true
|
||||
recent_projects = { path = "../recent_projects" }
|
||||
recent_projects.workspace = true
|
||||
regex.workspace = true
|
||||
release_channel = { path = "../release_channel" }
|
||||
rope = { path = "../rope" }
|
||||
rpc = { path = "../rpc" }
|
||||
release_channel.workspace = true
|
||||
rope.workspace = true
|
||||
rpc.workspace = true
|
||||
rsa = "0.4"
|
||||
rust-embed.workspace = true
|
||||
schemars.workspace = true
|
||||
search = { path = "../search" }
|
||||
semantic_index = { path = "../semantic_index" }
|
||||
search.workspace = true
|
||||
semantic_index.workspace = true
|
||||
serde.workspace = true
|
||||
serde_derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings = { path = "../settings" }
|
||||
settings.workspace = true
|
||||
shellexpand = "2.1.0"
|
||||
simplelog = "0.9"
|
||||
smallvec.workspace = true
|
||||
smol.workspace = true
|
||||
sum_tree = { path = "../sum_tree" }
|
||||
sum_tree.workspace = true
|
||||
tempfile.workspace = true
|
||||
terminal_view = { path = "../terminal_view" }
|
||||
text = { path = "../text" }
|
||||
theme = { path = "../theme" }
|
||||
theme_selector = { path = "../theme_selector" }
|
||||
terminal_view.workspace = true
|
||||
text.workspace = true
|
||||
theme.workspace = true
|
||||
theme_selector.workspace = true
|
||||
thiserror.workspace = true
|
||||
tiny_http = "0.8"
|
||||
toml.workspace = true
|
||||
tree-sitter-bash.workspace = true
|
||||
tree-sitter-beancount.workspace = true
|
||||
tree-sitter-c-sharp.workspace = true
|
||||
tree-sitter-c.workspace = true
|
||||
tree-sitter-cpp.workspace = true
|
||||
|
@ -123,6 +124,7 @@ tree-sitter-go.workspace = true
|
|||
tree-sitter-gomod.workspace = true
|
||||
tree-sitter-gowork.workspace = true
|
||||
tree-sitter-haskell.workspace = true
|
||||
tree-sitter-hcl.workspace = true
|
||||
tree-sitter-heex.workspace = true
|
||||
tree-sitter-html.workspace = true
|
||||
tree-sitter-json.workspace = true
|
||||
|
@ -130,6 +132,7 @@ tree-sitter-lua.workspace = true
|
|||
tree-sitter-markdown.workspace = true
|
||||
tree-sitter-nix.workspace = true
|
||||
tree-sitter-nu.workspace = true
|
||||
tree-sitter-ocaml.workspace = true
|
||||
tree-sitter-php.workspace = true
|
||||
tree-sitter-proto.workspace = true
|
||||
tree-sitter-purescript.workspace = true
|
||||
|
@ -148,22 +151,22 @@ tree-sitter-zig.workspace = true
|
|||
tree-sitter.workspace = true
|
||||
url.workspace = true
|
||||
urlencoding = "2.1.2"
|
||||
util = { path = "../util" }
|
||||
util.workspace = true
|
||||
uuid.workspace = true
|
||||
vim = { path = "../vim" }
|
||||
welcome = { path = "../welcome" }
|
||||
workspace = { path = "../workspace" }
|
||||
zed_actions = { path = "../zed_actions" }
|
||||
vim.workspace = true
|
||||
welcome.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
call = { path = "../call", features = ["test-support"] }
|
||||
editor = { path = "../editor", features = ["test-support"] }
|
||||
gpui = { path = "../gpui", features = ["test-support"] }
|
||||
language = { path = "../language", features = ["test-support"] }
|
||||
project = { path = "../project", features = ["test-support"] }
|
||||
text = { path = "../text", features = ["test-support"] }
|
||||
call = { workspace = true, features = ["test-support"] }
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
project = { workspace = true, features = ["test-support"] }
|
||||
text = { workspace = true, features = ["test-support"] }
|
||||
unindent.workspace = true
|
||||
workspace = { path = "../workspace", features = ["test-support"] }
|
||||
workspace = { workspace = true, features = ["test-support"] }
|
||||
|
||||
[package.metadata.bundle-dev]
|
||||
icon = ["resources/app-icon-preview@2x.png", "resources/app-icon-preview.png"]
|
||||
|
|
|
@ -25,6 +25,7 @@ mod json;
|
|||
mod language_plugin;
|
||||
mod lua;
|
||||
mod nu;
|
||||
mod ocaml;
|
||||
mod php;
|
||||
mod purescript;
|
||||
mod python;
|
||||
|
@ -66,6 +67,7 @@ pub fn init(
|
|||
};
|
||||
|
||||
language("bash", tree_sitter_bash::language(), vec![]);
|
||||
language("beancount", tree_sitter_beancount::language(), vec![]);
|
||||
language(
|
||||
"c",
|
||||
tree_sitter_c::language(),
|
||||
|
@ -302,6 +304,16 @@ pub fn init(
|
|||
tree_sitter_nu::language(),
|
||||
vec![Arc::new(nu::NuLanguageServer {})],
|
||||
);
|
||||
language(
|
||||
"ocaml",
|
||||
tree_sitter_ocaml::language_ocaml(),
|
||||
vec![Arc::new(ocaml::OCamlLspAdapter)],
|
||||
);
|
||||
language(
|
||||
"ocaml-interface",
|
||||
tree_sitter_ocaml::language_ocaml_interface(),
|
||||
vec![Arc::new(ocaml::OCamlLspAdapter)],
|
||||
);
|
||||
language(
|
||||
"vue",
|
||||
tree_sitter_vue::language(),
|
||||
|
@ -313,6 +325,8 @@ pub fn init(
|
|||
vec![Arc::new(uiua::UiuaLanguageServer {})],
|
||||
);
|
||||
language("proto", tree_sitter_proto::language(), vec![]);
|
||||
language("terraform", tree_sitter_hcl::language(), vec![]);
|
||||
language("hcl", tree_sitter_hcl::language(), vec![]);
|
||||
|
||||
if let Ok(children) = std::fs::read_dir(&*PLUGINS_DIR) {
|
||||
for child in children {
|
||||
|
|
3
crates/zed/src/languages/beancount/config.toml
Normal file
3
crates/zed/src/languages/beancount/config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = "Beancount"
|
||||
path_suffixes = ["beancount"]
|
||||
brackets = [{ start = "\"", end = "\"", close = false, newline = false }]
|
21
crates/zed/src/languages/beancount/highlights.scm
Normal file
21
crates/zed/src/languages/beancount/highlights.scm
Normal file
|
@ -0,0 +1,21 @@
|
|||
(comment) @comment
|
||||
(headline) @comment
|
||||
[
|
||||
(payee)
|
||||
(narration)
|
||||
(string)
|
||||
] @string
|
||||
|
||||
(number) @number
|
||||
(date) @function
|
||||
(currency) @constant
|
||||
(account) @identifier
|
||||
|
||||
[
|
||||
(option)
|
||||
(include)
|
||||
(open)
|
||||
(balance)
|
||||
(pad)
|
||||
(close)
|
||||
] @keyword
|
|
@ -1,9 +1,13 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use futures::StreamExt;
|
||||
use gpui::AppContext;
|
||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::LanguageServerBinary;
|
||||
use node_runtime::NodeRuntime;
|
||||
use project::project_settings::ProjectSettings;
|
||||
use serde_json::Value;
|
||||
use settings::Settings;
|
||||
use smol::fs;
|
||||
use std::{
|
||||
any::Any,
|
||||
|
@ -13,6 +17,7 @@ use std::{
|
|||
};
|
||||
use util::ResultExt;
|
||||
|
||||
const SERVER_NAME: &'static str = "elm-language-server";
|
||||
const SERVER_PATH: &'static str = "node_modules/@elm-tooling/elm-language-server/out/node/index.js";
|
||||
|
||||
fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
|
||||
|
@ -32,7 +37,7 @@ impl ElmLspAdapter {
|
|||
#[async_trait]
|
||||
impl LspAdapter for ElmLspAdapter {
|
||||
fn name(&self) -> LanguageServerName {
|
||||
LanguageServerName("elm-language-server".into())
|
||||
LanguageServerName(SERVER_NAME.into())
|
||||
}
|
||||
|
||||
fn short_name(&self) -> &'static str {
|
||||
|
@ -88,6 +93,27 @@ impl LspAdapter for ElmLspAdapter {
|
|||
) -> Option<LanguageServerBinary> {
|
||||
get_cached_server_binary(container_dir, &*self.node).await
|
||||
}
|
||||
|
||||
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
||||
// elm-language-server expects workspace didChangeConfiguration notification
|
||||
// params to be the same as lsp initialization_options
|
||||
let override_options = ProjectSettings::get_global(cx)
|
||||
.lsp
|
||||
.get(SERVER_NAME)
|
||||
.and_then(|s| s.initialization_options.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
match override_options.clone().as_object_mut() {
|
||||
Some(op) => {
|
||||
// elm-language-server requests workspace configuration
|
||||
// for the `elmLS` section, so we have to nest
|
||||
// another copy of initialization_options there
|
||||
op.insert("elmLS".into(), override_options);
|
||||
serde_json::to_value(op).unwrap_or_default()
|
||||
}
|
||||
None => override_options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_cached_server_binary(
|
||||
|
|
|
@ -398,7 +398,6 @@ mod tests {
|
|||
let highlight_type = grammar.highlight_id_for_name("type").unwrap();
|
||||
let highlight_keyword = grammar.highlight_id_for_name("keyword").unwrap();
|
||||
let highlight_number = grammar.highlight_id_for_name("number").unwrap();
|
||||
let highlight_field = grammar.highlight_id_for_name("property").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
language
|
||||
|
@ -454,7 +453,7 @@ mod tests {
|
|||
Some(CodeLabel {
|
||||
text: "two.Three a.Bcd".to_string(),
|
||||
filter_range: 0..9,
|
||||
runs: vec![(4..9, highlight_field), (12..15, highlight_type)],
|
||||
runs: vec![(12..15, highlight_type)],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
(identifier) @variable
|
||||
(type_identifier) @type
|
||||
(field_identifier) @property
|
||||
(field_identifier) @variable.member
|
||||
|
||||
(keyed_element
|
||||
.
|
||||
(literal_element
|
||||
(identifier) @variable.member))
|
||||
|
||||
(call_expression
|
||||
function: (identifier) @function)
|
||||
|
@ -15,6 +19,15 @@
|
|||
(method_declaration
|
||||
name: (field_identifier) @function.method)
|
||||
|
||||
[
|
||||
"("
|
||||
")"
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"--"
|
||||
"-"
|
||||
|
|
|
@ -7,20 +7,21 @@
|
|||
"func" @context
|
||||
name: (identifier) @name
|
||||
parameters: (parameter_list
|
||||
"(" @context
|
||||
")" @context)) @item
|
||||
"("
|
||||
")")) @item
|
||||
|
||||
(method_declaration
|
||||
"func" @context
|
||||
receiver: (parameter_list
|
||||
"(" @context
|
||||
(parameter_declaration
|
||||
name: (_) @name
|
||||
type: (_) @context)
|
||||
")" @context)
|
||||
name: (field_identifier) @name
|
||||
parameters: (parameter_list
|
||||
"(" @context
|
||||
")" @context)) @item
|
||||
"("
|
||||
")")) @item
|
||||
|
||||
(const_declaration
|
||||
"const" @context
|
||||
|
@ -40,4 +41,4 @@
|
|||
")" @context)) @item
|
||||
|
||||
(field_declaration
|
||||
name: (_) @name) @item
|
||||
name: (_) @name) @item
|
||||
|
|
26
crates/zed/src/languages/haskell/outline.scm
Normal file
26
crates/zed/src/languages/haskell/outline.scm
Normal file
|
@ -0,0 +1,26 @@
|
|||
(adt
|
||||
"data" @context
|
||||
name: (type) @name) @item
|
||||
|
||||
(type_alias
|
||||
"type" @context
|
||||
name: (type) @name) @item
|
||||
|
||||
(newtype
|
||||
"newtype" @context
|
||||
name: (type) @name) @item
|
||||
|
||||
(signature
|
||||
name: (variable) @name) @item
|
||||
|
||||
(class
|
||||
"class" @context
|
||||
(class_head) @name) @item
|
||||
|
||||
(instance
|
||||
"instance" @context
|
||||
(instance_head) @name) @item
|
||||
|
||||
(foreign_import
|
||||
"foreign" @context
|
||||
(impent) @name) @item
|
13
crates/zed/src/languages/hcl/config.toml
Normal file
13
crates/zed/src/languages/hcl/config.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = "HCL"
|
||||
path_suffixes = ["hcl"]
|
||||
line_comments = ["# ", "// "]
|
||||
block_comment = ["/*", "*/"]
|
||||
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 = ["comment", "string"] },
|
||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
]
|
117
crates/zed/src/languages/hcl/highlights.scm
Normal file
117
crates/zed/src/languages/hcl/highlights.scm
Normal file
|
@ -0,0 +1,117 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/hcl/highlights.scm
|
||||
; highlights.scm
|
||||
[
|
||||
"!"
|
||||
"\*"
|
||||
"/"
|
||||
"%"
|
||||
"\+"
|
||||
"-"
|
||||
">"
|
||||
">="
|
||||
"<"
|
||||
"<="
|
||||
"=="
|
||||
"!="
|
||||
"&&"
|
||||
"||"
|
||||
] @operator
|
||||
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
"("
|
||||
")"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"."
|
||||
".*"
|
||||
","
|
||||
"[*]"
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(ellipsis)
|
||||
"\?"
|
||||
"=>"
|
||||
] @punctuation.special
|
||||
|
||||
[
|
||||
":"
|
||||
"="
|
||||
] @punctuation
|
||||
|
||||
[
|
||||
"for"
|
||||
"endfor"
|
||||
"in"
|
||||
"if"
|
||||
"else"
|
||||
"endif"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
(quoted_template_start) ; "
|
||||
(quoted_template_end) ; "
|
||||
(template_literal) ; non-interpolation/directive content
|
||||
] @string
|
||||
|
||||
[
|
||||
(heredoc_identifier) ; END
|
||||
(heredoc_start) ; << or <<-
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(template_interpolation_start) ; ${
|
||||
(template_interpolation_end) ; }
|
||||
(template_directive_start) ; %{
|
||||
(template_directive_end) ; }
|
||||
(strip_marker) ; ~
|
||||
] @punctuation.special
|
||||
|
||||
(numeric_lit) @number
|
||||
|
||||
(bool_lit) @boolean
|
||||
|
||||
(null_lit) @constant
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(identifier) @variable
|
||||
|
||||
(body
|
||||
(block
|
||||
(identifier) @keyword))
|
||||
|
||||
(body
|
||||
(block
|
||||
(body
|
||||
(block
|
||||
(identifier) @type))))
|
||||
|
||||
(function_call
|
||||
(identifier) @function)
|
||||
|
||||
(attribute
|
||||
(identifier) @variable)
|
||||
|
||||
; { key: val }
|
||||
;
|
||||
; highlight identifier keys as though they were block attributes
|
||||
(object_elem
|
||||
key:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)))
|
||||
|
||||
; var.foo, data.bar
|
||||
;
|
||||
; first element in get_attr is a variable.builtin or a reference to a variable.builtin
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)
|
||||
(get_attr
|
||||
(identifier) @variable))
|
11
crates/zed/src/languages/hcl/indents.scm
Normal file
11
crates/zed/src/languages/hcl/indents.scm
Normal file
|
@ -0,0 +1,11 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/indents.scm
|
||||
[
|
||||
(block)
|
||||
(object)
|
||||
(tuple)
|
||||
(function_call)
|
||||
] @indent
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
6
crates/zed/src/languages/hcl/injections.scm
Normal file
6
crates/zed/src/languages/hcl/injections.scm
Normal file
|
@ -0,0 +1,6 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/injections.scm
|
||||
|
||||
(heredoc_template
|
||||
(template_literal) @content
|
||||
(heredoc_identifier) @language
|
||||
(#downcase! @language))
|
6
crates/zed/src/languages/ocaml-interface/brackets.scm
Normal file
6
crates/zed/src/languages/ocaml-interface/brackets.scm
Normal file
|
@ -0,0 +1,6 @@
|
|||
("(" @open ")" @close)
|
||||
("{" @open "}" @close)
|
||||
("<" @open ">" @close)
|
||||
|
||||
("sig" @open "end" @close)
|
||||
("object" @open "end" @close)
|
13
crates/zed/src/languages/ocaml-interface/config.toml
Normal file
13
crates/zed/src/languages/ocaml-interface/config.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = "OCaml Interface"
|
||||
path_suffixes = ["mli"]
|
||||
block_comment = ["(* ", "*)"]
|
||||
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 = true },
|
||||
{ start = "sig", end = " end", close = true, newline = true },
|
||||
# HACK: For some reason `object` alone does not work
|
||||
{ start = "object ", end = "end", close = true, newline = true },
|
||||
]
|
1
crates/zed/src/languages/ocaml-interface/highlights.scm
Symbolic link
1
crates/zed/src/languages/ocaml-interface/highlights.scm
Symbolic link
|
@ -0,0 +1 @@
|
|||
../ocaml/highlights.scm
|
21
crates/zed/src/languages/ocaml-interface/indents.scm
Normal file
21
crates/zed/src/languages/ocaml-interface/indents.scm
Normal file
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
(type_binding)
|
||||
|
||||
(value_specification)
|
||||
(method_specification)
|
||||
|
||||
(external)
|
||||
(field_declaration)
|
||||
] @indent
|
||||
|
||||
(_ "<" ">" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
|
||||
(_ "object" @start "end" @end) @indent
|
||||
|
||||
(signature
|
||||
"sig" @start
|
||||
"end" @end) @indent
|
||||
|
||||
";;" @outdent
|
48
crates/zed/src/languages/ocaml-interface/outline.scm
Normal file
48
crates/zed/src/languages/ocaml-interface/outline.scm
Normal file
|
@ -0,0 +1,48 @@
|
|||
(module_type_definition
|
||||
"module" @context
|
||||
"type" @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(module_definition
|
||||
"module" @context
|
||||
(module_binding name: (_) @name)) @item
|
||||
|
||||
(type_definition
|
||||
"type" @context
|
||||
(type_binding name: (_) @name)) @item
|
||||
|
||||
(class_definition
|
||||
"class" @context
|
||||
(class_binding
|
||||
"virtual"? @context
|
||||
name: (_) @name)) @item
|
||||
|
||||
(class_type_definition
|
||||
"class" @context
|
||||
"type" @context
|
||||
(class_type_binding
|
||||
"virtual"? @context
|
||||
name: (_) @name)) @item
|
||||
|
||||
(instance_variable_definition
|
||||
"val" @context
|
||||
"method"? @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(method_specification
|
||||
"method" @context
|
||||
"virtual"? @context
|
||||
(method_name) @name) @item
|
||||
|
||||
(value_specification
|
||||
"val" @context
|
||||
(value_name) @name) @item
|
||||
|
||||
(external
|
||||
"external" @context
|
||||
(value_name) @name) @item
|
||||
|
||||
(exception_definition
|
||||
"exception" @context
|
||||
(constructor_declaration
|
||||
(constructor_name) @name)) @item
|
317
crates/zed/src/languages/ocaml.rs
Normal file
317
crates/zed/src/languages/ocaml.rs
Normal file
|
@ -0,0 +1,317 @@
|
|||
use std::{any::Any, ops::Range, path::PathBuf, sync::Arc};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use language::{CodeLabel, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||
use lsp::{CompletionItemKind, LanguageServerBinary, SymbolKind};
|
||||
use rope::Rope;
|
||||
|
||||
const OPERATOR_CHAR: [char; 17] = [
|
||||
'~', '!', '?', '%', '<', ':', '.', '$', '&', '*', '+', '-', '/', '=', '>', '@', '^',
|
||||
];
|
||||
|
||||
pub struct OCamlLspAdapter;
|
||||
|
||||
#[async_trait]
|
||||
impl LspAdapter for OCamlLspAdapter {
|
||||
fn name(&self) -> LanguageServerName {
|
||||
LanguageServerName("ocamllsp".into())
|
||||
}
|
||||
|
||||
fn short_name(&self) -> &'static str {
|
||||
"ocaml"
|
||||
}
|
||||
|
||||
async fn fetch_latest_server_version(
|
||||
&self,
|
||||
_: &dyn LspAdapterDelegate,
|
||||
) -> Result<Box<dyn 'static + Send + Any>> {
|
||||
Ok(Box::new(()))
|
||||
}
|
||||
|
||||
async fn fetch_server_binary(
|
||||
&self,
|
||||
_: Box<dyn 'static + Send + Any>,
|
||||
_: PathBuf,
|
||||
_: &dyn LspAdapterDelegate,
|
||||
) -> Result<LanguageServerBinary> {
|
||||
Err(anyhow!(
|
||||
"ocamllsp (ocaml-language-server) must be installed manually."
|
||||
))
|
||||
}
|
||||
|
||||
async fn cached_server_binary(
|
||||
&self,
|
||||
_: PathBuf,
|
||||
_: &dyn LspAdapterDelegate,
|
||||
) -> Option<LanguageServerBinary> {
|
||||
Some(LanguageServerBinary {
|
||||
path: "ocamllsp".into(),
|
||||
arguments: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
fn can_be_reinstalled(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn label_for_completion(
|
||||
&self,
|
||||
completion: &lsp::CompletionItem,
|
||||
language: &Arc<language::Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let name = &completion.label;
|
||||
let detail = completion.detail.as_ref().map(|s| s.replace("\n", " "));
|
||||
|
||||
match completion.kind.zip(detail) {
|
||||
// Error of 'b : ('a, 'b) result
|
||||
// Stack_overflow : exn
|
||||
Some((CompletionItemKind::CONSTRUCTOR | CompletionItemKind::ENUM_MEMBER, detail)) => {
|
||||
let (argument, return_t) = detail
|
||||
.split_once("->")
|
||||
.map_or((None, detail.as_str()), |(arg, typ)| {
|
||||
(Some(arg.trim()), typ.trim())
|
||||
});
|
||||
|
||||
let constr_decl = argument.map_or(name.to_string(), |argument| {
|
||||
format!("{} of {}", name, argument)
|
||||
});
|
||||
|
||||
let constr_host = if return_t.ends_with("exn") {
|
||||
"exception "
|
||||
} else {
|
||||
"type t = "
|
||||
};
|
||||
|
||||
let source_host = Rope::from([constr_host, &constr_decl].join(" "));
|
||||
let mut source_highlight = {
|
||||
let constr_host_len = constr_host.len() + 1;
|
||||
|
||||
language.highlight_text(
|
||||
&source_host,
|
||||
Range {
|
||||
start: constr_host_len,
|
||||
end: constr_host_len + constr_decl.len(),
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
let signature_host: Rope = Rope::from(format!("let _ : {} = ()", return_t));
|
||||
|
||||
// We include the ': ' in the range as we use it later
|
||||
let mut signature_highlight =
|
||||
language.highlight_text(&signature_host, 6..8 + return_t.len());
|
||||
|
||||
if let Some(last) = source_highlight.last() {
|
||||
let offset = last.0.end + 1;
|
||||
|
||||
signature_highlight.iter_mut().for_each(|(r, _)| {
|
||||
r.start += offset;
|
||||
r.end += offset;
|
||||
});
|
||||
};
|
||||
|
||||
Some(CodeLabel {
|
||||
text: format!("{} : {}", constr_decl, return_t),
|
||||
runs: {
|
||||
source_highlight.append(&mut signature_highlight);
|
||||
source_highlight
|
||||
},
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
// version : string
|
||||
// NOTE: (~|?) are omitted as we don't use them in the fuzzy filtering
|
||||
Some((CompletionItemKind::FIELD, detail))
|
||||
if name.starts_with("~") || name.starts_with("?") =>
|
||||
{
|
||||
let label = name.trim_start_matches(&['~', '?']);
|
||||
let text = format!("{} : {}", label, detail);
|
||||
|
||||
let signature_host = Rope::from(format!("let _ : {} = ()", detail));
|
||||
let signature_highlight =
|
||||
&mut language.highlight_text(&signature_host, 6..8 + detail.len());
|
||||
|
||||
let offset = label.len() + 1;
|
||||
for (r, _) in signature_highlight.iter_mut() {
|
||||
r.start += offset;
|
||||
r.end += offset;
|
||||
}
|
||||
|
||||
let mut label_highlight = vec![(
|
||||
0..0 + label.len(),
|
||||
language.grammar()?.highlight_id_for_name("property")?,
|
||||
)];
|
||||
|
||||
Some(CodeLabel {
|
||||
text,
|
||||
runs: {
|
||||
label_highlight.append(signature_highlight);
|
||||
label_highlight
|
||||
},
|
||||
filter_range: 0..label.len(),
|
||||
})
|
||||
}
|
||||
// version: string;
|
||||
Some((CompletionItemKind::FIELD, detail)) => {
|
||||
let (_record_t, field_t) = detail.split_once("->")?;
|
||||
|
||||
let text = format!("{}: {};", name, field_t);
|
||||
let source_host: Rope = Rope::from(format!("type t = {{ {} }}", text));
|
||||
|
||||
let runs: Vec<(Range<usize>, language::HighlightId)> =
|
||||
language.highlight_text(&source_host, 11..11 + text.len());
|
||||
|
||||
Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
// let* : 'a t -> ('a -> 'b t) -> 'b t
|
||||
Some((CompletionItemKind::VALUE, detail))
|
||||
if name.contains(OPERATOR_CHAR)
|
||||
|| (name.starts_with("let") && name.contains(OPERATOR_CHAR)) =>
|
||||
{
|
||||
let text = format!("{} : {}", name, detail);
|
||||
|
||||
let source_host = Rope::from(format!("let ({}) : {} = ()", name, detail));
|
||||
let mut runs = language.highlight_text(&source_host, 5..6 + text.len());
|
||||
|
||||
if runs.len() > 1 {
|
||||
// ')'
|
||||
runs.remove(1);
|
||||
|
||||
for run in &mut runs[1..] {
|
||||
run.0.start -= 1;
|
||||
run.0.end -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
// version : Version.t list -> Version.t option Lwt.t
|
||||
Some((CompletionItemKind::VALUE, detail)) => {
|
||||
let text = format!("{} : {}", name, detail);
|
||||
|
||||
let source_host = Rope::from(format!("let {} = ()", text));
|
||||
let runs = language.highlight_text(&source_host, 4..4 + text.len());
|
||||
|
||||
Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
// status : string
|
||||
Some((CompletionItemKind::METHOD, detail)) => {
|
||||
let text = format!("{} : {}", name, detail);
|
||||
|
||||
let method_host = Rope::from(format!("class c : object method {} end", text));
|
||||
let runs = language.highlight_text(&method_host, 24..24 + text.len());
|
||||
|
||||
Some(CodeLabel {
|
||||
text,
|
||||
runs,
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
Some((kind, _)) => {
|
||||
let highlight_name = match kind {
|
||||
CompletionItemKind::MODULE | CompletionItemKind::INTERFACE => "title",
|
||||
CompletionItemKind::KEYWORD => "keyword",
|
||||
CompletionItemKind::TYPE_PARAMETER => "type",
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(CodeLabel {
|
||||
text: name.clone(),
|
||||
runs: vec![(
|
||||
0..name.len(),
|
||||
language.grammar()?.highlight_id_for_name(highlight_name)?,
|
||||
)],
|
||||
filter_range: 0..name.len(),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn label_for_symbol(
|
||||
&self,
|
||||
name: &str,
|
||||
kind: SymbolKind,
|
||||
language: &Arc<language::Language>,
|
||||
) -> Option<CodeLabel> {
|
||||
let (text, filter_range, display_range) = match kind {
|
||||
SymbolKind::PROPERTY => {
|
||||
let text = format!("type t = {{ {}: (); }}", name);
|
||||
let filter_range: Range<usize> = 0..name.len();
|
||||
let display_range = 11..11 + name.len();
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::FUNCTION
|
||||
if name.contains(OPERATOR_CHAR)
|
||||
|| (name.starts_with("let") && name.contains(OPERATOR_CHAR)) =>
|
||||
{
|
||||
let text = format!("let ({}) () = ()", name);
|
||||
|
||||
let filter_range = 5..5 + name.len();
|
||||
let display_range = 0..filter_range.end + 1;
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::FUNCTION => {
|
||||
let text = format!("let {} () = ()", name);
|
||||
|
||||
let filter_range = 4..4 + name.len();
|
||||
let display_range = 0..filter_range.end;
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::CONSTRUCTOR => {
|
||||
let text = format!("type t = {}", name);
|
||||
let filter_range = 0..name.len();
|
||||
let display_range = 9..9 + name.len();
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::MODULE => {
|
||||
let text = format!("module {} = struct end", name);
|
||||
let filter_range = 7..7 + name.len();
|
||||
let display_range = 0..filter_range.end;
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::CLASS => {
|
||||
let text = format!("class {} = object end", name);
|
||||
let filter_range = 6..6 + name.len();
|
||||
let display_range = 0..filter_range.end;
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::METHOD => {
|
||||
let text = format!("class c = object method {} = () end", name);
|
||||
let filter_range = 0..name.len();
|
||||
let display_range = 17..24 + name.len();
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
SymbolKind::STRING => {
|
||||
let text = format!("type {} = T", name);
|
||||
let filter_range = 5..5 + name.len();
|
||||
let display_range = 0..filter_range.end;
|
||||
(text, filter_range, display_range)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(CodeLabel {
|
||||
runs: language.highlight_text(&text.as_str().into(), display_range.clone()),
|
||||
text: text[display_range].to_string(),
|
||||
filter_range,
|
||||
})
|
||||
}
|
||||
}
|
12
crates/zed/src/languages/ocaml/brackets.scm
Normal file
12
crates/zed/src/languages/ocaml/brackets.scm
Normal file
|
@ -0,0 +1,12 @@
|
|||
("(" @open ")" @close)
|
||||
("[" @open "]" @close)
|
||||
("[|" @open "|]" @close)
|
||||
("{" @open "}" @close)
|
||||
("<" @open ">" @close)
|
||||
("\"" @open "\"" @close)
|
||||
|
||||
("begin" @open "end" @close)
|
||||
("struct" @open "end" @close)
|
||||
("sig" @open "end" @close)
|
||||
("object" @open "end" @close)
|
||||
("do" @open "done" @close)
|
18
crates/zed/src/languages/ocaml/config.toml
Normal file
18
crates/zed/src/languages/ocaml/config.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
name = "OCaml"
|
||||
path_suffixes = ["ml"]
|
||||
block_comment = ["(* ", "*)"]
|
||||
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 = true, not_in = ["string"] },
|
||||
{ start = "(", end = ")", close = true, newline = true },
|
||||
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
|
||||
{ start = "begin", end = " end", close = true, newline = true },
|
||||
{ start = "struct", end = " end", close = true, newline = true },
|
||||
{ start = "sig", end = " end", close = true, newline = true },
|
||||
# HACK: For some reason `object` alone does not work
|
||||
{ start = "object ", end = "end", close = true, newline = true },
|
||||
{ start = "do", end = " done", close = true, newline = true }
|
||||
]
|
142
crates/zed/src/languages/ocaml/highlights.scm
Normal file
142
crates/zed/src/languages/ocaml/highlights.scm
Normal file
|
@ -0,0 +1,142 @@
|
|||
; Modules
|
||||
;--------
|
||||
|
||||
[(module_name) (module_type_name)] @title
|
||||
|
||||
; Types
|
||||
;------
|
||||
|
||||
[(class_name) (class_type_name) (type_constructor)] @type
|
||||
|
||||
[(constructor_name) (tag)] @constructor
|
||||
|
||||
; Functions
|
||||
;----------
|
||||
|
||||
(let_binding
|
||||
pattern: (value_name) @function
|
||||
(parameter))
|
||||
|
||||
(let_binding
|
||||
pattern: (value_name) @function
|
||||
body: [(fun_expression) (function_expression)])
|
||||
|
||||
(value_specification (value_name) @function)
|
||||
|
||||
(external (value_name) @function)
|
||||
|
||||
(method_name) @function
|
||||
|
||||
(infix_expression
|
||||
left: (value_path (value_name) @function)
|
||||
operator: (concat_operator) @operator
|
||||
(#eq? @operator "@@"))
|
||||
|
||||
(infix_expression
|
||||
operator: (rel_operator) @operator
|
||||
right: (value_path (value_name) @function)
|
||||
(#eq? @operator "|>"))
|
||||
|
||||
(application_expression
|
||||
function: (value_path (value_name) @function))
|
||||
|
||||
; Variables
|
||||
;----------
|
||||
|
||||
[(type_variable) (value_pattern)] @variable
|
||||
|
||||
; Properties
|
||||
;-----------
|
||||
|
||||
[(label_name) (field_name) (instance_variable_name)] @property
|
||||
|
||||
; Constants
|
||||
;----------
|
||||
|
||||
(boolean) @boolean
|
||||
|
||||
[(number) (signed_number)] @number
|
||||
|
||||
[(string) (character)] @string
|
||||
|
||||
(quoted_string "{" @string "}" @string) @string
|
||||
(quoted_string_content) @string
|
||||
|
||||
|
||||
(escape_sequence) @string.escape
|
||||
|
||||
[
|
||||
(conversion_specification)
|
||||
(pretty_printing_indication)
|
||||
] @punctuation.special
|
||||
|
||||
; Operators
|
||||
;----------
|
||||
|
||||
(match_expression (match_operator) @keyword)
|
||||
|
||||
(value_definition [(let_operator) (let_and_operator)] @keyword)
|
||||
|
||||
[
|
||||
(prefix_operator)
|
||||
(sign_operator)
|
||||
(pow_operator)
|
||||
(mult_operator)
|
||||
(add_operator)
|
||||
(concat_operator)
|
||||
(rel_operator)
|
||||
(and_operator)
|
||||
(or_operator)
|
||||
(assign_operator)
|
||||
(hash_operator)
|
||||
(indexing_operator)
|
||||
(let_operator)
|
||||
(let_and_operator)
|
||||
(match_operator)
|
||||
] @operator
|
||||
|
||||
["*" "#" "::" "<-"] @operator
|
||||
|
||||
; Keywords
|
||||
;---------
|
||||
|
||||
[
|
||||
"and" "as" "assert" "begin" "class" "constraint" "do" "done" "downto" "else"
|
||||
"end" "exception" "external" "for" "fun" "function" "functor" "if" "in"
|
||||
"include" "inherit" "initializer" "lazy" "let" "match" "method" "module"
|
||||
"mutable" "new" "nonrec" "object" "of" "open" "private" "rec" "sig" "struct"
|
||||
"then" "to" "try" "type" "val" "virtual" "when" "while" "with"
|
||||
] @keyword
|
||||
|
||||
; Punctuation
|
||||
;------------
|
||||
|
||||
["(" ")" "[" "]" "{" "}" "[|" "|]" "[<" "[>"] @punctuation.bracket
|
||||
|
||||
(object_type ["<" ">"] @punctuation.bracket)
|
||||
|
||||
[
|
||||
"," "." ";" ":" "=" "|" "~" "?" "+" "-" "!" ">" "&"
|
||||
"->" ";;" ":>" "+=" ":=" ".."
|
||||
] @punctuation.delimiter
|
||||
|
||||
; Attributes
|
||||
;-----------
|
||||
|
||||
[
|
||||
(attribute)
|
||||
(item_attribute)
|
||||
(floating_attribute)
|
||||
(extension)
|
||||
(item_extension)
|
||||
(quoted_extension)
|
||||
(quoted_item_extension)
|
||||
"%"
|
||||
] @attribute
|
||||
|
||||
(attribute_id) @tag
|
||||
|
||||
; Comments
|
||||
;---------
|
||||
|
||||
[(comment) (line_number_directive) (directive) (shebang)] @comment
|
43
crates/zed/src/languages/ocaml/indents.scm
Normal file
43
crates/zed/src/languages/ocaml/indents.scm
Normal file
|
@ -0,0 +1,43 @@
|
|||
[
|
||||
(let_binding)
|
||||
(type_binding)
|
||||
|
||||
(method_definition)
|
||||
|
||||
(external)
|
||||
(value_specification)
|
||||
(method_specification)
|
||||
|
||||
(match_case)
|
||||
|
||||
(function_expression)
|
||||
|
||||
(field_declaration)
|
||||
(field_expression)
|
||||
] @indent
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "[|" "|]" @end) @indent
|
||||
(_ "<" ">" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
|
||||
(_ "object" @start "end" @end) @indent
|
||||
|
||||
(structure
|
||||
"struct" @start
|
||||
"end" @end) @indent
|
||||
|
||||
(signature
|
||||
"sig" @start
|
||||
"end" @end) @indent
|
||||
|
||||
(parenthesized_expression
|
||||
"begin" @start
|
||||
"end") @indent
|
||||
|
||||
(do_clause
|
||||
"do" @start
|
||||
"done" @end) @indent
|
||||
|
||||
";;" @outdent
|
59
crates/zed/src/languages/ocaml/outline.scm
Normal file
59
crates/zed/src/languages/ocaml/outline.scm
Normal file
|
@ -0,0 +1,59 @@
|
|||
(_structure_item/value_definition
|
||||
"let" @context
|
||||
(let_binding
|
||||
pattern: (_) @name)) @item
|
||||
|
||||
(_structure_item/exception_definition
|
||||
"exception" @context
|
||||
(constructor_declaration
|
||||
(constructor_name) @name)) @item
|
||||
|
||||
(_structure_item/module_definition
|
||||
"module" @context
|
||||
(module_binding
|
||||
name: (module_name) @name)) @item
|
||||
|
||||
(module_type_definition
|
||||
"module" @context
|
||||
"type" @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(type_definition
|
||||
"type" @context
|
||||
(type_binding name: (_) @name)) @item
|
||||
|
||||
(value_specification
|
||||
"val" @context
|
||||
(value_name) @name) @item
|
||||
|
||||
(class_definition
|
||||
"class" @context
|
||||
(class_binding
|
||||
"virtual"? @context
|
||||
name: (_) @name)) @item
|
||||
|
||||
(class_type_definition
|
||||
"class" @context
|
||||
"type" @context
|
||||
(class_type_binding
|
||||
"virtual"? @context
|
||||
name: (_) @name)) @item
|
||||
|
||||
(instance_variable_definition
|
||||
"val" @context
|
||||
"method"? @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(method_specification
|
||||
"method" @context
|
||||
"virtual"? @context
|
||||
(method_name) @name) @item
|
||||
|
||||
(method_definition
|
||||
"method" @context
|
||||
"virtual"? @context
|
||||
name: (_) @name) @item
|
||||
|
||||
(external
|
||||
"external" @context
|
||||
(value_name) @name) @item
|
13
crates/zed/src/languages/terraform/config.toml
Normal file
13
crates/zed/src/languages/terraform/config.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = "Terraform"
|
||||
path_suffixes = ["tf", "tfvars"]
|
||||
line_comments = ["# ", "// "]
|
||||
block_comment = ["/*", "*/"]
|
||||
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 = ["comment", "string"] },
|
||||
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
{ start = "/*", end = " */", close = true, newline = false, not_in = ["comment", "string"] },
|
||||
]
|
159
crates/zed/src/languages/terraform/highlights.scm
Normal file
159
crates/zed/src/languages/terraform/highlights.scm
Normal file
|
@ -0,0 +1,159 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/hcl/highlights.scm
|
||||
; highlights.scm
|
||||
[
|
||||
"!"
|
||||
"\*"
|
||||
"/"
|
||||
"%"
|
||||
"\+"
|
||||
"-"
|
||||
">"
|
||||
">="
|
||||
"<"
|
||||
"<="
|
||||
"=="
|
||||
"!="
|
||||
"&&"
|
||||
"||"
|
||||
] @operator
|
||||
|
||||
[
|
||||
"{"
|
||||
"}"
|
||||
"["
|
||||
"]"
|
||||
"("
|
||||
")"
|
||||
] @punctuation.bracket
|
||||
|
||||
[
|
||||
"."
|
||||
".*"
|
||||
","
|
||||
"[*]"
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(ellipsis)
|
||||
"\?"
|
||||
"=>"
|
||||
] @punctuation.special
|
||||
|
||||
[
|
||||
":"
|
||||
"="
|
||||
] @punctuation
|
||||
|
||||
[
|
||||
"for"
|
||||
"endfor"
|
||||
"in"
|
||||
"if"
|
||||
"else"
|
||||
"endif"
|
||||
] @keyword
|
||||
|
||||
[
|
||||
(quoted_template_start) ; "
|
||||
(quoted_template_end) ; "
|
||||
(template_literal) ; non-interpolation/directive content
|
||||
] @string
|
||||
|
||||
[
|
||||
(heredoc_identifier) ; END
|
||||
(heredoc_start) ; << or <<-
|
||||
] @punctuation.delimiter
|
||||
|
||||
[
|
||||
(template_interpolation_start) ; ${
|
||||
(template_interpolation_end) ; }
|
||||
(template_directive_start) ; %{
|
||||
(template_directive_end) ; }
|
||||
(strip_marker) ; ~
|
||||
] @punctuation.special
|
||||
|
||||
(numeric_lit) @number
|
||||
|
||||
(bool_lit) @boolean
|
||||
|
||||
(null_lit) @constant
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(identifier) @variable
|
||||
|
||||
(body
|
||||
(block
|
||||
(identifier) @keyword))
|
||||
|
||||
(body
|
||||
(block
|
||||
(body
|
||||
(block
|
||||
(identifier) @type))))
|
||||
|
||||
(function_call
|
||||
(identifier) @function)
|
||||
|
||||
(attribute
|
||||
(identifier) @variable)
|
||||
|
||||
; { key: val }
|
||||
;
|
||||
; highlight identifier keys as though they were block attributes
|
||||
(object_elem
|
||||
key:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)))
|
||||
|
||||
; var.foo, data.bar
|
||||
;
|
||||
; first element in get_attr is a variable.builtin or a reference to a variable.builtin
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable)
|
||||
(get_attr
|
||||
(identifier) @variable))
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/cb79d2446196d25607eb1d982c96939abdf67b8e/queries/terraform/highlights.scm
|
||||
; Terraform specific references
|
||||
;
|
||||
;
|
||||
; local/module/data/var/output
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "data" "var" "local" "module" "output"))
|
||||
(get_attr
|
||||
(identifier) @variable))
|
||||
|
||||
; path.root/cwd/module
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#eq? @type "path"))
|
||||
(get_attr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "root" "cwd" "module")))
|
||||
|
||||
; terraform.workspace
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#eq? @type "terraform"))
|
||||
(get_attr
|
||||
(identifier) @variable
|
||||
(#any-of? @variable "workspace")))
|
||||
|
||||
; Terraform specific keywords
|
||||
; FIXME: ideally only for identifiers under a `variable` block to minimize false positives
|
||||
((identifier) @type
|
||||
(#any-of? @type "bool" "string" "number" "object" "tuple" "list" "map" "set" "any"))
|
||||
|
||||
(object_elem
|
||||
val:
|
||||
(expression
|
||||
(variable_expr
|
||||
(identifier) @type
|
||||
(#any-of? @type "bool" "string" "number" "object" "tuple" "list" "map" "set" "any"))))
|
14
crates/zed/src/languages/terraform/indents.scm
Normal file
14
crates/zed/src/languages/terraform/indents.scm
Normal file
|
@ -0,0 +1,14 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/indents.scm
|
||||
[
|
||||
(block)
|
||||
(object)
|
||||
(tuple)
|
||||
(function_call)
|
||||
] @indent
|
||||
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/terraform/indents.scm
|
||||
; inherits: hcl
|
9
crates/zed/src/languages/terraform/injections.scm
Normal file
9
crates/zed/src/languages/terraform/injections.scm
Normal file
|
@ -0,0 +1,9 @@
|
|||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/hcl/injections.scm
|
||||
|
||||
(heredoc_template
|
||||
(template_literal) @content
|
||||
(heredoc_identifier) @language
|
||||
(#downcase! @language))
|
||||
|
||||
; https://github.com/nvim-treesitter/nvim-treesitter/blob/ce4adf11cfe36fc5b0e5bcdce0c7c6e8fbc9798a/queries/terraform/injections.scm
|
||||
; inherits: hcl
|
|
@ -44,7 +44,7 @@ use std::{
|
|||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
use theme::{ActiveTheme, ThemeRegistry, ThemeSettings};
|
||||
use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
|
||||
use util::{
|
||||
async_maybe,
|
||||
http::{self, HttpClient, ZedHttpClient},
|
||||
|
@ -127,6 +127,7 @@ fn main() {
|
|||
AppCommitSha::set_global(AppCommitSha(build_sha.into()), cx);
|
||||
}
|
||||
|
||||
SystemAppearance::init(cx);
|
||||
OpenListener::set_global(listener.clone(), cx);
|
||||
|
||||
load_embedded_fonts(cx);
|
||||
|
@ -475,6 +476,7 @@ fn init_paths() {
|
|||
fn init_logger() {
|
||||
if stdout_is_a_pty() {
|
||||
Builder::new()
|
||||
.parse_default_env()
|
||||
.format(|buf, record| {
|
||||
use env_logger::fmt::Color;
|
||||
|
||||
|
@ -814,7 +816,7 @@ async fn load_login_shell_environment() -> Result<()> {
|
|||
"SHELL environment variable is not assigned so we can't source login environment variables",
|
||||
)?;
|
||||
let output = Command::new(&shell)
|
||||
.args(["-lic", &format!("echo {marker} && /usr/bin/env -0")])
|
||||
.args(["-l", "-i", "-c", &format!("echo {marker}; /usr/bin/env -0")])
|
||||
.output()
|
||||
.await
|
||||
.context("failed to spawn login shell to source login environment variables")?;
|
||||
|
@ -896,27 +898,39 @@ fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
|
|||
if let Some(theme_registry) =
|
||||
cx.update(|cx| ThemeRegistry::global(cx).clone()).log_err()
|
||||
{
|
||||
if let Some(()) = theme_registry
|
||||
.load_user_themes(&paths::THEMES_DIR.clone(), fs)
|
||||
let themes_dir = paths::THEMES_DIR.as_ref();
|
||||
match fs
|
||||
.metadata(themes_dir)
|
||||
.await
|
||||
.log_err()
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|m| m.is_dir)
|
||||
{
|
||||
cx.update(|cx| {
|
||||
let mut theme_settings = ThemeSettings::get_global(cx).clone();
|
||||
|
||||
if let Some(requested_theme) = theme_settings.requested_theme.clone() {
|
||||
if let Some(_theme) = theme_settings.switch_theme(&requested_theme, cx)
|
||||
{
|
||||
ThemeSettings::override_global(theme_settings, cx);
|
||||
}
|
||||
}
|
||||
})
|
||||
.log_err();
|
||||
Some(is_dir) => {
|
||||
anyhow::ensure!(is_dir, "Themes dir path {themes_dir:?} is not a directory")
|
||||
}
|
||||
None => {
|
||||
fs.create_dir(themes_dir).await.with_context(|| {
|
||||
format!("Failed to create themes dir at path {themes_dir:?}")
|
||||
})?;
|
||||
}
|
||||
}
|
||||
theme_registry.load_user_themes(themes_dir, fs).await?;
|
||||
cx.update(|cx| {
|
||||
let mut theme_settings = ThemeSettings::get_global(cx).clone();
|
||||
if let Some(theme_selection) = theme_settings.theme_selection.clone() {
|
||||
let theme_name = theme_selection.theme(*SystemAppearance::global(cx));
|
||||
|
||||
if let Some(_theme) = theme_settings.switch_theme(&theme_name, cx) {
|
||||
ThemeSettings::override_global(theme_settings, cx);
|
||||
}
|
||||
}
|
||||
})?;
|
||||
}
|
||||
anyhow::Ok(())
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
//todo!(linux): Port fsevents to linux
|
||||
|
@ -945,11 +959,14 @@ fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
|
|||
cx.update(|cx| {
|
||||
let mut theme_settings = ThemeSettings::get_global(cx).clone();
|
||||
|
||||
if let Some(requested_theme) =
|
||||
theme_settings.requested_theme.clone()
|
||||
if let Some(theme_selection) =
|
||||
theme_settings.theme_selection.clone()
|
||||
{
|
||||
let theme_name =
|
||||
theme_selection.theme(*SystemAppearance::global(cx));
|
||||
|
||||
if let Some(_theme) =
|
||||
theme_settings.switch_theme(&requested_theme, cx)
|
||||
theme_settings.switch_theme(&theme_name, cx)
|
||||
{
|
||||
ThemeSettings::override_global(theme_settings, cx);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use cli::{ipc, IpcHandshake};
|
||||
use cli::{ipc::IpcSender, CliRequest, CliResponse};
|
||||
use collections::HashMap;
|
||||
use editor::scroll::Autoscroll;
|
||||
use editor::Editor;
|
||||
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
|
@ -10,7 +11,6 @@ use gpui::{AppContext, AsyncAppContext, Global};
|
|||
use itertools::Itertools;
|
||||
use language::{Bias, Point};
|
||||
use release_channel::parse_zed_link;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::prelude::OsStrExt;
|
||||
use std::path::Path;
|
||||
|
@ -176,7 +176,7 @@ pub async fn handle_cli_connection(
|
|||
if let Some(request) = requests.next().await {
|
||||
match request {
|
||||
CliRequest::Open { paths, wait } => {
|
||||
let mut caret_positions = HashMap::new();
|
||||
let mut caret_positions = HashMap::default();
|
||||
|
||||
let paths = if paths.is_empty() {
|
||||
workspace::last_opened_workspace_paths()
|
||||
|
|
|
@ -353,7 +353,7 @@ fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewCo
|
|||
toolbar.add_item(buffer_search_bar.clone(), cx);
|
||||
|
||||
let quick_action_bar =
|
||||
cx.new_view(|_| QuickActionBar::new(buffer_search_bar, workspace));
|
||||
cx.new_view(|cx| QuickActionBar::new(buffer_search_bar, workspace, cx));
|
||||
toolbar.add_item(quick_action_bar, cx);
|
||||
let diagnostic_editor_controls = cx.new_view(|_| diagnostics::ToolbarControls::new());
|
||||
toolbar.add_item(diagnostic_editor_controls, cx);
|
||||
|
@ -733,6 +733,7 @@ fn open_settings_file(
|
|||
mod tests {
|
||||
use super::*;
|
||||
use assets::Assets;
|
||||
use collections::HashSet;
|
||||
use editor::{scroll::Autoscroll, DisplayPoint, Editor};
|
||||
use gpui::{
|
||||
actions, Action, AnyWindowHandle, AppContext, AssetSource, Entity, TestAppContext,
|
||||
|
@ -742,10 +743,7 @@ mod tests {
|
|||
use project::{project_settings::ProjectSettings, Project, ProjectPath};
|
||||
use serde_json::json;
|
||||
use settings::{handle_settings_file_changes, watch_config_file, SettingsStore};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use theme::{ThemeRegistry, ThemeSettings};
|
||||
use workspace::{
|
||||
item::{Item, ItemHandle},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue