Compare commits
6 commits
main
...
cherry-pic
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7d58eb200b | ||
![]() |
87c9f6a52e | ||
![]() |
059a409235 | ||
![]() |
5c450693fa | ||
![]() |
910507d7e5 | ||
![]() |
3d48f14248 |
16 changed files with 293 additions and 69 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -4960,6 +4960,7 @@ dependencies = [
|
||||||
"theme",
|
"theme",
|
||||||
"time",
|
"time",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
|
"tree-sitter-c",
|
||||||
"tree-sitter-html",
|
"tree-sitter-html",
|
||||||
"tree-sitter-python",
|
"tree-sitter-python",
|
||||||
"tree-sitter-rust",
|
"tree-sitter-rust",
|
||||||
|
@ -20193,7 +20194,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.198.0"
|
version = "0.198.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activity_indicator",
|
"activity_indicator",
|
||||||
"agent",
|
"agent",
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
"ctrl-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
"ctrl-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
||||||
"alt-shift-f10": "task::Spawn",
|
"alt-shift-f10": "task::Spawn",
|
||||||
"ctrl-e": "file_finder::Toggle",
|
"ctrl-e": "file_finder::Toggle",
|
||||||
"ctrl-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
// "ctrl-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
||||||
"ctrl-shift-n": "file_finder::Toggle",
|
"ctrl-shift-n": "file_finder::Toggle",
|
||||||
"ctrl-shift-a": "command_palette::Toggle",
|
"ctrl-shift-a": "command_palette::Toggle",
|
||||||
"shift shift": "command_palette::Toggle",
|
"shift shift": "command_palette::Toggle",
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
"cmd-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
"cmd-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
||||||
"ctrl-alt-r": "task::Spawn",
|
"ctrl-alt-r": "task::Spawn",
|
||||||
"cmd-e": "file_finder::Toggle",
|
"cmd-e": "file_finder::Toggle",
|
||||||
"cmd-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
// "cmd-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
||||||
"cmd-shift-o": "file_finder::Toggle",
|
"cmd-shift-o": "file_finder::Toggle",
|
||||||
"cmd-shift-a": "command_palette::Toggle",
|
"cmd-shift-a": "command_palette::Toggle",
|
||||||
"shift shift": "command_palette::Toggle",
|
"shift shift": "command_palette::Toggle",
|
||||||
|
|
|
@ -295,7 +295,7 @@ mod tests {
|
||||||
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Box::new(|_| panic!("Did not expect to hit this code path")),
|
Box::new(|_| {}),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -883,6 +883,7 @@ impl FakeTransport {
|
||||||
break Err(anyhow!("exit in response to request"));
|
break Err(anyhow!("exit in response to request"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let success = response.success;
|
||||||
let message =
|
let message =
|
||||||
serde_json::to_string(&Message::Response(response)).unwrap();
|
serde_json::to_string(&Message::Response(response)).unwrap();
|
||||||
|
|
||||||
|
@ -893,6 +894,25 @@ impl FakeTransport {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if request.command == dap_types::requests::Initialize::COMMAND
|
||||||
|
&& success
|
||||||
|
{
|
||||||
|
let message = serde_json::to_string(&Message::Event(Box::new(
|
||||||
|
dap_types::messages::Events::Initialized(Some(
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
writer
|
||||||
|
.write_all(
|
||||||
|
TransportDelegate::build_rpc_message(message)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
writer.flush().await.unwrap();
|
writer.flush().await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ test-support = [
|
||||||
"theme/test-support",
|
"theme/test-support",
|
||||||
"util/test-support",
|
"util/test-support",
|
||||||
"workspace/test-support",
|
"workspace/test-support",
|
||||||
|
"tree-sitter-c",
|
||||||
"tree-sitter-rust",
|
"tree-sitter-rust",
|
||||||
"tree-sitter-typescript",
|
"tree-sitter-typescript",
|
||||||
"tree-sitter-html",
|
"tree-sitter-html",
|
||||||
|
@ -76,6 +77,7 @@ telemetry.workspace = true
|
||||||
text.workspace = true
|
text.workspace = true
|
||||||
time.workspace = true
|
time.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
|
tree-sitter-c = { workspace = true, optional = true }
|
||||||
tree-sitter-html = { workspace = true, optional = true }
|
tree-sitter-html = { workspace = true, optional = true }
|
||||||
tree-sitter-rust = { workspace = true, optional = true }
|
tree-sitter-rust = { workspace = true, optional = true }
|
||||||
tree-sitter-typescript = { workspace = true, optional = true }
|
tree-sitter-typescript = { workspace = true, optional = true }
|
||||||
|
@ -106,6 +108,7 @@ settings = { workspace = true, features = ["test-support"] }
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
text = { workspace = true, features = ["test-support"] }
|
text = { workspace = true, features = ["test-support"] }
|
||||||
theme = { workspace = true, features = ["test-support"] }
|
theme = { workspace = true, features = ["test-support"] }
|
||||||
|
tree-sitter-c.workspace = true
|
||||||
tree-sitter-html.workspace = true
|
tree-sitter-html.workspace = true
|
||||||
tree-sitter-rust.workspace = true
|
tree-sitter-rust.workspace = true
|
||||||
tree-sitter-typescript.workspace = true
|
tree-sitter-typescript.workspace = true
|
||||||
|
|
|
@ -1305,6 +1305,7 @@ impl Default for SelectionHistoryMode {
|
||||||
///
|
///
|
||||||
/// Similarly, you might want to disable scrolling if you don't want the viewport to
|
/// Similarly, you might want to disable scrolling if you don't want the viewport to
|
||||||
/// move.
|
/// move.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SelectionEffects {
|
pub struct SelectionEffects {
|
||||||
nav_history: Option<bool>,
|
nav_history: Option<bool>,
|
||||||
completions: bool,
|
completions: bool,
|
||||||
|
@ -2944,10 +2945,12 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let selection_anchors = self.selections.disjoint_anchors();
|
||||||
|
|
||||||
if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
|
if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
self.buffer.update(cx, |buffer, cx| {
|
||||||
buffer.set_active_selections(
|
buffer.set_active_selections(
|
||||||
&self.selections.disjoint_anchors(),
|
&selection_anchors,
|
||||||
self.selections.line_mode,
|
self.selections.line_mode,
|
||||||
self.cursor_shape,
|
self.cursor_shape,
|
||||||
cx,
|
cx,
|
||||||
|
@ -2964,9 +2967,8 @@ impl Editor {
|
||||||
self.select_next_state = None;
|
self.select_next_state = None;
|
||||||
self.select_prev_state = None;
|
self.select_prev_state = None;
|
||||||
self.select_syntax_node_history.try_clear();
|
self.select_syntax_node_history.try_clear();
|
||||||
self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
|
self.invalidate_autoclose_regions(&selection_anchors, buffer);
|
||||||
self.snippet_stack
|
self.snippet_stack.invalidate(&selection_anchors, buffer);
|
||||||
.invalidate(&self.selections.disjoint_anchors(), buffer);
|
|
||||||
self.take_rename(false, window, cx);
|
self.take_rename(false, window, cx);
|
||||||
|
|
||||||
let newest_selection = self.selections.newest_anchor();
|
let newest_selection = self.selections.newest_anchor();
|
||||||
|
@ -4047,7 +4049,8 @@ impl Editor {
|
||||||
// then don't insert that closing bracket again; just move the selection
|
// then don't insert that closing bracket again; just move the selection
|
||||||
// past the closing bracket.
|
// past the closing bracket.
|
||||||
let should_skip = selection.end == region.range.end.to_point(&snapshot)
|
let should_skip = selection.end == region.range.end.to_point(&snapshot)
|
||||||
&& text.as_ref() == region.pair.end.as_str();
|
&& text.as_ref() == region.pair.end.as_str()
|
||||||
|
&& snapshot.contains_str_at(region.range.end, text.as_ref());
|
||||||
if should_skip {
|
if should_skip {
|
||||||
let anchor = snapshot.anchor_after(selection.end);
|
let anchor = snapshot.anchor_after(selection.end);
|
||||||
new_selections
|
new_selections
|
||||||
|
@ -4973,13 +4976,17 @@ impl Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove any autoclose regions that no longer contain their selection.
|
/// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
|
||||||
fn invalidate_autoclose_regions(
|
fn invalidate_autoclose_regions(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut selections: &[Selection<Anchor>],
|
mut selections: &[Selection<Anchor>],
|
||||||
buffer: &MultiBufferSnapshot,
|
buffer: &MultiBufferSnapshot,
|
||||||
) {
|
) {
|
||||||
self.autoclose_regions.retain(|state| {
|
self.autoclose_regions.retain(|state| {
|
||||||
|
if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while let Some(selection) = selections.get(i) {
|
while let Some(selection) = selections.get(i) {
|
||||||
if selection.end.cmp(&state.range.start, buffer).is_lt() {
|
if selection.end.cmp(&state.range.start, buffer).is_lt() {
|
||||||
|
@ -5891,18 +5898,20 @@ impl Editor {
|
||||||
text: new_text[common_prefix_len..].into(),
|
text: new_text[common_prefix_len..].into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.transact(window, cx, |this, window, cx| {
|
self.transact(window, cx, |editor, window, cx| {
|
||||||
if let Some(mut snippet) = snippet {
|
if let Some(mut snippet) = snippet {
|
||||||
snippet.text = new_text.to_string();
|
snippet.text = new_text.to_string();
|
||||||
this.insert_snippet(&ranges, snippet, window, cx).log_err();
|
editor
|
||||||
|
.insert_snippet(&ranges, snippet, window, cx)
|
||||||
|
.log_err();
|
||||||
} else {
|
} else {
|
||||||
this.buffer.update(cx, |buffer, cx| {
|
editor.buffer.update(cx, |multi_buffer, cx| {
|
||||||
let auto_indent = match completion.insert_text_mode {
|
let auto_indent = match completion.insert_text_mode {
|
||||||
Some(InsertTextMode::AS_IS) => None,
|
Some(InsertTextMode::AS_IS) => None,
|
||||||
_ => this.autoindent_mode.clone(),
|
_ => editor.autoindent_mode.clone(),
|
||||||
};
|
};
|
||||||
let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
|
let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
|
||||||
buffer.edit(edits, auto_indent, cx);
|
multi_buffer.edit(edits, auto_indent, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (buffer, edits) in linked_edits {
|
for (buffer, edits) in linked_edits {
|
||||||
|
@ -5921,8 +5930,9 @@ impl Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refresh_inline_completion(true, false, window, cx);
|
editor.refresh_inline_completion(true, false, window, cx);
|
||||||
});
|
});
|
||||||
|
self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
|
||||||
|
|
||||||
let show_new_completions_on_confirm = completion
|
let show_new_completions_on_confirm = completion
|
||||||
.confirm
|
.confirm
|
||||||
|
@ -9562,27 +9572,46 @@ impl Editor {
|
||||||
// Check whether the just-entered snippet ends with an auto-closable bracket.
|
// Check whether the just-entered snippet ends with an auto-closable bracket.
|
||||||
if self.autoclose_regions.is_empty() {
|
if self.autoclose_regions.is_empty() {
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
for selection in &mut self.selections.all::<Point>(cx) {
|
let mut all_selections = self.selections.all::<Point>(cx);
|
||||||
|
for selection in &mut all_selections {
|
||||||
let selection_head = selection.head();
|
let selection_head = selection.head();
|
||||||
let Some(scope) = snapshot.language_scope_at(selection_head) else {
|
let Some(scope) = snapshot.language_scope_at(selection_head) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bracket_pair = None;
|
let mut bracket_pair = None;
|
||||||
let next_chars = snapshot.chars_at(selection_head).collect::<String>();
|
let max_lookup_length = scope
|
||||||
let prev_chars = snapshot
|
.brackets()
|
||||||
.reversed_chars_at(selection_head)
|
.map(|(pair, _)| {
|
||||||
.collect::<String>();
|
pair.start
|
||||||
for (pair, enabled) in scope.brackets() {
|
.as_str()
|
||||||
if enabled
|
.chars()
|
||||||
&& pair.close
|
.count()
|
||||||
&& prev_chars.starts_with(pair.start.as_str())
|
.max(pair.end.as_str().chars().count())
|
||||||
&& next_chars.starts_with(pair.end.as_str())
|
})
|
||||||
{
|
.max();
|
||||||
bracket_pair = Some(pair.clone());
|
if let Some(max_lookup_length) = max_lookup_length {
|
||||||
break;
|
let next_text = snapshot
|
||||||
|
.chars_at(selection_head)
|
||||||
|
.take(max_lookup_length)
|
||||||
|
.collect::<String>();
|
||||||
|
let prev_text = snapshot
|
||||||
|
.reversed_chars_at(selection_head)
|
||||||
|
.take(max_lookup_length)
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
for (pair, enabled) in scope.brackets() {
|
||||||
|
if enabled
|
||||||
|
&& pair.close
|
||||||
|
&& prev_text.starts_with(pair.start.as_str())
|
||||||
|
&& next_text.starts_with(pair.end.as_str())
|
||||||
|
{
|
||||||
|
bracket_pair = Some(pair.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pair) = bracket_pair {
|
if let Some(pair) = bracket_pair {
|
||||||
let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
|
let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
|
||||||
let autoclose_enabled =
|
let autoclose_enabled =
|
||||||
|
|
|
@ -13400,6 +13400,178 @@ async fn test_as_is_completions(cx: &mut TestAppContext) {
|
||||||
cx.assert_editor_state("fn a() {}\n unsafeˇ");
|
cx.assert_editor_state("fn a() {}\n unsafeˇ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_panic_during_c_completions(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
let language =
|
||||||
|
Arc::try_unwrap(languages::language("c", tree_sitter_c::LANGUAGE.into())).unwrap();
|
||||||
|
let mut cx = EditorLspTestContext::new(
|
||||||
|
language,
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
|
..lsp::CompletionOptions::default()
|
||||||
|
}),
|
||||||
|
..lsp::ServerCapabilities::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.set_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
ˇ",
|
||||||
|
);
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("#", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("i", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("n", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#inˇ",
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::List(lsp::CompletionList {
|
||||||
|
is_incomplete: false,
|
||||||
|
item_defaults: None,
|
||||||
|
items: vec![lsp::CompletionItem {
|
||||||
|
kind: Some(lsp::CompletionItemKind::SNIPPET),
|
||||||
|
label_details: Some(lsp::CompletionItemLabelDetails {
|
||||||
|
detail: Some("header".to_string()),
|
||||||
|
description: None,
|
||||||
|
}),
|
||||||
|
label: " include".to_string(),
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
|
range: lsp::Range {
|
||||||
|
start: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 1,
|
||||||
|
},
|
||||||
|
end: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new_text: "include \"$0\"".to_string(),
|
||||||
|
})),
|
||||||
|
sort_text: Some("40b67681include".to_string()),
|
||||||
|
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
||||||
|
filter_text: Some("include".to_string()),
|
||||||
|
insert_text: Some("include \"$0\"".to_string()),
|
||||||
|
..lsp::CompletionItem::default()
|
||||||
|
}],
|
||||||
|
})))
|
||||||
|
});
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.show_completions(&ShowCompletions { trigger: None }, window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.confirm_completion(&ConfirmCompletion::default(), window, cx)
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include \"ˇ\"",
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::List(lsp::CompletionList {
|
||||||
|
is_incomplete: true,
|
||||||
|
item_defaults: None,
|
||||||
|
items: vec![lsp::CompletionItem {
|
||||||
|
kind: Some(lsp::CompletionItemKind::FILE),
|
||||||
|
label: "AGL/".to_string(),
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
|
range: lsp::Range {
|
||||||
|
start: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 10,
|
||||||
|
},
|
||||||
|
end: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new_text: "AGL/".to_string(),
|
||||||
|
})),
|
||||||
|
sort_text: Some("40b67681AGL/".to_string()),
|
||||||
|
insert_text_format: Some(lsp::InsertTextFormat::PLAIN_TEXT),
|
||||||
|
filter_text: Some("AGL/".to_string()),
|
||||||
|
insert_text: Some("AGL/".to_string()),
|
||||||
|
..lsp::CompletionItem::default()
|
||||||
|
}],
|
||||||
|
})))
|
||||||
|
});
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.show_completions(&ShowCompletions { trigger: None }, window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.confirm_completion(&ConfirmCompletion::default(), window, cx)
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
r##"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include "AGL/ˇ"##,
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("\"", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
r##"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include "AGL/"ˇ"##,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_no_duplicated_completion_requests(cx: &mut TestAppContext) {
|
async fn test_no_duplicated_completion_requests(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
|
@ -1004,12 +1004,13 @@ impl X11Client {
|
||||||
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
||||||
let keysym = state.xkb.key_get_one_sym(code);
|
let keysym = state.xkb.key_get_one_sym(code);
|
||||||
|
|
||||||
// should be called after key_get_one_sym
|
|
||||||
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
|
||||||
|
|
||||||
if keysym.is_modifier_key() {
|
if keysym.is_modifier_key() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be called after key_get_one_sym
|
||||||
|
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
||||||
|
|
||||||
if let Some(mut compose_state) = state.compose_state.take() {
|
if let Some(mut compose_state) = state.compose_state.take() {
|
||||||
compose_state.feed(keysym);
|
compose_state.feed(keysym);
|
||||||
match compose_state.status() {
|
match compose_state.status() {
|
||||||
|
@ -1067,12 +1068,13 @@ impl X11Client {
|
||||||
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
||||||
let keysym = state.xkb.key_get_one_sym(code);
|
let keysym = state.xkb.key_get_one_sym(code);
|
||||||
|
|
||||||
// should be called after key_get_one_sym
|
|
||||||
state.xkb.update_key(code, xkbc::KeyDirection::Up);
|
|
||||||
|
|
||||||
if keysym.is_modifier_key() {
|
if keysym.is_modifier_key() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be called after key_get_one_sym
|
||||||
|
state.xkb.update_key(code, xkbc::KeyDirection::Up);
|
||||||
|
|
||||||
keystroke
|
keystroke
|
||||||
};
|
};
|
||||||
drop(state);
|
drop(state);
|
||||||
|
|
|
@ -167,10 +167,10 @@ impl Anchor {
|
||||||
if *self == Anchor::min() || *self == Anchor::max() {
|
if *self == Anchor::min() || *self == Anchor::max() {
|
||||||
true
|
true
|
||||||
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||||
excerpt.contains(self)
|
(self.text_anchor == excerpt.range.context.start
|
||||||
&& (self.text_anchor == excerpt.range.context.start
|
|| self.text_anchor == excerpt.range.context.end
|
||||||
|| self.text_anchor == excerpt.range.context.end
|
|| self.text_anchor.is_valid(&excerpt.buffer))
|
||||||
|| self.text_anchor.is_valid(&excerpt.buffer))
|
&& excerpt.contains(self)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use dap::client::DebugAdapterClient;
|
use dap::client::DebugAdapterClient;
|
||||||
use gpui::{App, AppContext, Subscription};
|
use gpui::{App, Subscription};
|
||||||
|
|
||||||
use super::session::{Session, SessionStateEvent};
|
use super::session::{Session, SessionStateEvent};
|
||||||
|
|
||||||
|
@ -19,14 +19,6 @@ pub fn intercept_debug_sessions<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||||
let client = session.adapter_client().unwrap();
|
let client = session.adapter_client().unwrap();
|
||||||
register_default_handlers(session, &client, cx);
|
register_default_handlers(session, &client, cx);
|
||||||
configure(&client);
|
configure(&client);
|
||||||
cx.background_spawn(async move {
|
|
||||||
client
|
|
||||||
.fake_event(dap::messages::Events::Initialized(
|
|
||||||
Some(Default::default()),
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
|
@ -2269,7 +2269,7 @@ impl LspCommand for GetCompletions {
|
||||||
// the range based on the syntax tree.
|
// the range based on the syntax tree.
|
||||||
None => {
|
None => {
|
||||||
if self.position != clipped_position {
|
if self.position != clipped_position {
|
||||||
log::info!("completion out of expected range");
|
log::info!("completion out of expected range ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2483,7 +2483,9 @@ pub(crate) fn parse_completion_text_edit(
|
||||||
let start = snapshot.clip_point_utf16(range.start, Bias::Left);
|
let start = snapshot.clip_point_utf16(range.start, Bias::Left);
|
||||||
let end = snapshot.clip_point_utf16(range.end, Bias::Left);
|
let end = snapshot.clip_point_utf16(range.end, Bias::Left);
|
||||||
if start != range.start.0 || end != range.end.0 {
|
if start != range.start.0 || end != range.end.0 {
|
||||||
log::info!("completion out of expected range");
|
log::info!(
|
||||||
|
"completion out of expected range, start: {start:?}, end: {end:?}, range: {range:?}"
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
snapshot.anchor_before(start)..snapshot.anchor_after(end)
|
snapshot.anchor_before(start)..snapshot.anchor_after(end)
|
||||||
|
|
|
@ -99,7 +99,9 @@ impl Anchor {
|
||||||
} else if self.buffer_id != Some(buffer.remote_id) {
|
} else if self.buffer_id != Some(buffer.remote_id) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let fragment_id = buffer.fragment_id_for_anchor(self);
|
let Some(fragment_id) = buffer.try_fragment_id_for_anchor(self) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
||||||
fragment_cursor.seek(&Some(fragment_id), Bias::Left);
|
fragment_cursor.seek(&Some(fragment_id), Bias::Left);
|
||||||
fragment_cursor
|
fragment_cursor
|
||||||
|
|
|
@ -2330,10 +2330,19 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
||||||
|
self.try_fragment_id_for_anchor(anchor).unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"invalid anchor {:?}. buffer id: {}, version: {:?}",
|
||||||
|
anchor, self.remote_id, self.version,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fragment_id_for_anchor(&self, anchor: &Anchor) -> Option<&Locator> {
|
||||||
if *anchor == Anchor::MIN {
|
if *anchor == Anchor::MIN {
|
||||||
Locator::min_ref()
|
Some(Locator::min_ref())
|
||||||
} else if *anchor == Anchor::MAX {
|
} else if *anchor == Anchor::MAX {
|
||||||
Locator::max_ref()
|
Some(Locator::max_ref())
|
||||||
} else {
|
} else {
|
||||||
let anchor_key = InsertionFragmentKey {
|
let anchor_key = InsertionFragmentKey {
|
||||||
timestamp: anchor.timestamp,
|
timestamp: anchor.timestamp,
|
||||||
|
@ -2354,20 +2363,12 @@ impl BufferSnapshot {
|
||||||
insertion_cursor.prev();
|
insertion_cursor.prev();
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(insertion) = insertion_cursor.item().filter(|insertion| {
|
insertion_cursor
|
||||||
if cfg!(debug_assertions) {
|
.item()
|
||||||
insertion.timestamp == anchor.timestamp
|
.filter(|insertion| {
|
||||||
} else {
|
!cfg!(debug_assertions) || insertion.timestamp == anchor.timestamp
|
||||||
true
|
})
|
||||||
}
|
.map(|insertion| &insertion.fragment_id)
|
||||||
}) else {
|
|
||||||
panic!(
|
|
||||||
"invalid anchor {:?}. buffer id: {}, version: {:?}",
|
|
||||||
anchor, self.remote_id, self.version
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
&insertion.fragment_id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
description = "The fast, collaborative code editor."
|
description = "The fast, collaborative code editor."
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.198.0"
|
version = "0.198.1"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
authors = ["Zed Team <hi@zed.dev>"]
|
authors = ["Zed Team <hi@zed.dev>"]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
dev
|
preview
|
Loading…
Add table
Add a link
Reference in a new issue