Compare commits

...
Sign in to create a new pull request.

6 commits

Author SHA1 Message Date
Joseph T. Lyons
7d58eb200b zed 0.198.1 2025-08-01 14:15:54 -04:00
gcp-cherry-pick-bot[bot]
87c9f6a52e
debugger: Send initialized event from fake server at a more realistic time (cherry-pick #35446) (#35447)
Cherry-picked debugger: Send initialized event from fake server at a
more realistic time (#35446)

The spec says:

> ⬅️ Initialized Event
> This event indicates that the debug adapter is ready to accept
configuration requests (e.g. setBreakpoints, setExceptionBreakpoints).
>
> A debug adapter is expected to send this event when it is ready to
accept configuration requests (but not before the initialize request has
finished).

Previously in tests, `intercept_debug_sessions` was just spawning off a
background task to send the event after setting up the client, so the
event wasn't actually synchronized with the flow of messages in the way
the spec says it should be. This PR makes it so that the `FakeTransport`
injects the event right after a successful response to the initialize
request, and doesn't send it otherwise.

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-08-01 11:23:30 -04:00
gcp-cherry-pick-bot[bot]
059a409235
Fix panic with completion ranges and autoclose regions interop (cherry-pick #35408) (#35414)
Cherry-picked Fix panic with completion ranges and autoclose regions
interop (#35408)

As reported [in

Discord](https://discord.com/channels/869392257814519848/1106226198494859355/1398470747227426948)
C projects with `"` as "brackets" that autoclose, may invoke panics when
edited at the end of the file.

With a single selection-caret (`ˇ`), at the end of the file,
```c
ifndef BAR_H
#define BAR_H

#include <stdbool.h>

int fn_branch(bool do_branch1, bool do_branch2);

#endif // BAR_H
#include"ˇ"
```
gets an LSP response from clangd
```jsonc
{
  "filterText": "AGL/",
  "insertText": "AGL/",
  "insertTextFormat": 1,
  "kind": 17,
  "label": " AGL/",
  "labelDetails": {},
  "score": 0.78725427389144897,
  "sortText": "40b67681AGL/",
  "textEdit": {
    "newText": "AGL/",
    "range": { "end": { "character": 11, "line": 8 }, "start": { "character": 10, "line": 8 } }
  }
}
```

which replaces `"` after the caret (character/column 11, 0-indexed).
This is reasonable, as regular follow-up (proposed in further
completions), is a suffix + a closing `"`:

<img width="842" height="259" alt="image"

src="https://github.com/user-attachments/assets/ea56f621-7008-4ce2-99ba-87344ddf33d2"
/>

Yet when Zed handles user input of `"`, it panics due to multiple
reasons:

* after applying any snippet text edit, Zed did a selection change:

5537987630/crates/editor/src/editor.rs (L9539-L9545)
which caused eventual autoclose region invalidation:

5537987630/crates/editor/src/editor.rs (L2970)

This covers all cases that insert the `include""` text.

* after applying any user input and "plain" text edit, Zed did not
invalidate any autoclose regions at all, relying on the "bracket" (which
includes `"`) autoclose logic to rule edge cases out

* bracket autoclose logic detects previous `"` and considers the new
user input as a valid closure, hence no autoclose region needed.
But there is an autoclose bracket data after the plaintext completion
insertion (`AGL/`) really, and it's not invalidated after `"` handling

* in addition to that, `Anchor::is_valid` method in `text` panicked, and
required `fn try_fragment_id_for_anchor` to handle "pointing at odd,
after the end of the file, offset" cases as `false`

A test reproducing the feedback and 2 fixes added: proper, autoclose
region invalidation call which required the invalidation logic tweaked a
bit, and "superficial", "do not apply bad selections that cause panics"
fix in the editor to be more robust

Release Notes:

- Fixed panic with completion ranges and autoclose regions interop

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-08-01 08:39:10 +03:00
Peter Tripp
5c450693fa
jetbrains: Unmap cmd-k in Jetbrains keymap (#35443)
This only works after a delay in most situations because of the all
chorded `cmd-k` mappings in the so disable them for now.

Reported by @jer-k:
https://x.com/J_Kreutzbender/status/1951033355434336606

Release Notes:

- Undo mapping of `cmd-k` for Git Panel in default Jetbrains keymap
(thanks [@jer-k](https://github.com/jer-k))
2025-07-31 18:30:09 -04:00
gcp-cherry-pick-bot[bot]
910507d7e5
linux: Fix caps lock not working consistently for certain X11 systems (cherry-pick #35361) (#35365)
Cherry-picked linux: Fix caps lock not working consistently for certain
X11 systems (#35361)

Closes #35316

Bug in https://github.com/zed-industries/zed/pull/34514

Turns out you are not supposed to call `update_key` for modifiers on
`KeyPress`/`KeyRelease`, as modifiers are already updated in
`XkbStateNotify` events. Not sure why this only causes issues on a few
systems and works on others.

Tested on Ubuntu 24.04.2 LTS (initial bug) and Kubuntu 25.04 (worked
fine before too).

Release Notes:

- Fixed an issue where caps lock stopped working consistently on some
Linux X11 systems.

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2025-07-31 01:22:41 +05:30
Joseph T. Lyons
3d48f14248 v0.198.x preview 2025-07-30 12:07:29 -04:00
16 changed files with 293 additions and 69 deletions

3
Cargo.lock generated
View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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

View file

@ -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();
} }
} }

View file

@ -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

View file

@ -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 =

View file

@ -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, |_| {});

View file

@ -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);

View file

@ -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
} }

View file

@ -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();

View file

@ -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)

View file

@ -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

View file

@ -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
} }
} }

View file

@ -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>"]

View file

@ -1 +1 @@
dev preview