Compare commits

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

23 commits

Author SHA1 Message Date
Max Brunsfeld
c1c67a5025 zed 0.97.6 2023-08-08 12:35:38 -07:00
Piotr Osiewicz
cbaf7cc972 Piotr/optimize search selections with a limit (#2831)
/cc @nathansobo @maxbrunsfeld 

Release Notes:
- Fixed scrollbar selections causing noticeable slowdowns with large
quantities of selections.
2023-08-08 12:34:37 -07:00
Max Brunsfeld
c24c4063e3 Make LspAdapter::process_diagnostics synchronous (#2829)
When editing rust code, the project diagnostics view sometimes fails to
update, so that you have to close the view and re-open it to see the
correct state.

This PR fixes one possible cause of that problem. There was an async
step in between *receiving* diagnostics from the language server and
updating the diagnostics, due to an async call to
`LspAdapter::process_diagnostics`. This could cause the following
sequence of events to happen:

1. Rust-analyzer sends us new diagnostics for a file `a.rs`
2. We call `process_diagnostics` with those diagnostics
3. Rust-analyzer sends us a `WorkDoneProgress` message, indicating that
the "flycheck" (aka `cargo check`) process has completed
4. We update the project diagnostics view due to this message.
5. The `process_diagnostics` call for `a.rs` completes
6. 💥 We have the new diagnostics for `a.rs`, but do not update the
project diagnostics view again.

This PR fixes this bug by simply making `process_diagnostics`
synchronous. There is no I/O or expensive computation happening in that
method. If we need to make it asynchronous in the future, we need to
introduce a queue that ensures that `publishDiagnostics` and
`workDoneProgress` messages are processed serially.

Release Notes:

- Fixed a bug where the project diagnostics view would sometimes fail to
update properly when using Rust-analyzer.
2023-08-08 12:34:28 -07:00
Joseph T. Lyons
707da9bbbf v0.97.x stable 2023-08-02 13:50:08 -04:00
Mikayla Maki
c826010008 Halve opacity on wrap guides (#2815)
Wrap guides are a little too bright as is
2023-08-02 12:52:33 -04:00
Mikayla Maki
e928e1db4e disable wrap guides in the assitant panel (#2814)
Wrap guides do not look correct in the assistant due to it's current
header styling. Disable them in that context now.

Release Notes:

- Fix a visual bug displaying when enabling wrap guides in the
assistant.
2023-08-02 12:51:34 -04:00
Joseph T. Lyons
f5b1962b0e zed 0.97.5 2023-07-28 18:13:24 -04:00
Mikayla Maki
0b13c6bc84 Make wrap guides respect scroll position (#2810)
Release Notes:

- Fixed a visual bug when scrolling with wrap guides active
2023-07-28 18:11:23 -04:00
Joseph T. Lyons
75365249cc Update release action to choose between preview and stable URL in Discord announcements
This is what ChatGPT told me, so we'll see.
2023-07-28 15:12:46 -04:00
Conrad Irwin
1c2f5162bc Don't highlight project search matches either (#2807)
@JosephTLyons this is probably worth merging alongside #2803

- vim: Fix a bug where focusing project search results unexpectedly
entered visual mode
2023-07-28 14:31:22 -04:00
Conrad Irwin
209c68c85e Fix jumping to definition in a new file (#2803)
This is broken because vim currently sets settings only on the active
editor. Fix this by correcting the range on the currently active editor.

It would be nice (at some point) to refactor how vim sets settings, but
that's for another day.

Release Notes:

- vim: Fix bug when jumping to definition in new file accidentally
entered visual mode.
2023-07-28 14:30:58 -04:00
Mikayla Maki
023a617b30
zed 0.97.4 2023-07-27 16:36:49 -07:00
Mikayla Maki
286d302273
Make mode indicator follow vim enabled state (#2802)
There was a minor visual bug introduced in
https://github.com/zed-industries/zed/pull/2801, this PR corrects it.

Release Notes:

- N/A
2023-07-27 16:32:28 -07:00
Julia
4091a2004e
Avoid panic by accessing view handle by global in wrong window
View handles are window specific but this global will be doing things
in all windows, that would cause a panic when it attempted to update
a status bar mode indicator in a background window

Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
2023-07-27 16:32:20 -07:00
Joseph T. Lyons
9d4a2bfb58 Publish preview releases to discord (#2800)
Release Notes:

- N/A
2023-07-27 15:26:36 -04:00
Joseph T. Lyons
33e58d47ac zed 0.97.3 2023-07-27 14:30:24 -04:00
Mikayla Maki
056282f59b Downgrade our dependency on treesitter-cpp (#2799)
Our dependency on `tree-sitter-cpp` got upgraded to an incompatible
version despite semver 'guarantees'. This pins the dependency onto the
commit of version 0.20.0

Release Notes:

- Restored language detection for C++ (preview-only)
2023-07-27 14:21:16 -04:00
Antonio Scandurra
553b9601d1 zed 0.97.2 2023-07-27 14:47:09 +02:00
Antonio Scandurra
a166f0b56a Maintain cursor stack's position correctly when ascending the tree (#2795)
This fixes a bug that could cause the cursor to incorrectly report its
start when using `slice` or `seek_forward`, and then calling `prev`. We
didn't notice this because we were not testing those three methods
together.

I suppose this could explain some of the panics we've observed because
we do use `slice`/`seek_forward` followed by `prev` calls in production.
2023-07-27 14:45:38 +02:00
Joseph T. Lyons
badc2ec0e9 zed 0.97.1 2023-07-26 18:57:44 -04:00
Mikayla Maki
9c3c719ce0 Downgrade tree sitter elm to 5.6.4 (#2794)
The tree sitter elm parser contains a c symbol which collides with other
linked symbols. This PR downgrades the tree sitter elm parser to a
version which doesn't have this problem.

Release Notes:
- Fixed crash when parsing elm files
2023-07-26 18:55:24 -04:00
Mikayla Maki
3594b5e2a8 Block extra drag events in original drag handlers (#2793)
In https://github.com/zed-industries/zed/pull/2790 I added an extra drag
event on mouse_up which signaled the end of a drag event, as mouse_up
event themselves wouldn't reliably fire if users moved their mouse too
quickly. This broke the assumptions of the terminal element. This PR
adds filters to all current on_drag handlers which removes this new
event.

Release Notes:

- Fixed a bug causing terminal links to never open (preview only)
- Fixed a bug in terminal link detection causing it to miss files with a
`-` in it
2023-07-26 18:20:50 -04:00
Joseph T. Lyons
99d0ed4a76 v0.97.x preview 2023-07-26 13:27:34 -04:00
23 changed files with 306 additions and 170 deletions

View file

@ -6,14 +6,23 @@ jobs:
discord_release:
runs-on: ubuntu-latest
steps:
- name: Get appropriate URL
id: get-appropriate-url
run: |
if [ "${{ github.event.release.prerelease }}" == "true" ]; then
URL="https://zed.dev/releases/preview/latest"
else
URL="https://zed.dev/releases/stable/latest"
fi
echo "::set-output name=URL::$URL"
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v5.3.0
if: ${{ ! github.event.release.prerelease }}
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
content: |
📣 Zed ${{ github.event.release.tag_name }} was just released!
Restart your Zed or head to https://zed.dev/releases/stable/latest to grab it.
Restart your Zed or head to ${{ steps.get-appropriate-url.outputs.URL }} to grab it.
${{ github.event.release.body }}

24
Cargo.lock generated
View file

@ -6513,7 +6513,7 @@ dependencies = [
"theme",
"tiktoken-rs 0.5.0",
"tree-sitter",
"tree-sitter-cpp",
"tree-sitter-cpp 0.20.2",
"tree-sitter-elixir 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tree-sitter-json 0.19.0",
"tree-sitter-rust",
@ -8032,9 +8032,18 @@ dependencies = [
[[package]]
name = "tree-sitter-cpp"
version = "0.20.1"
version = "0.20.0"
source = "git+https://github.com/tree-sitter/tree-sitter-cpp?rev=f44509141e7e483323d2ec178f2d2e6c0fc041c1#f44509141e7e483323d2ec178f2d2e6c0fc041c1"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-cpp"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dbedbf4066bfab725b3f9e2a21530507419a7d2f98621d3c13213502b734ec0"
checksum = "1c88fd925d0333e63ac64e521f5bd79c53019e569ffbbccfeef346a326f459e9"
dependencies = [
"cc",
"tree-sitter",
@ -8070,9 +8079,8 @@ dependencies = [
[[package]]
name = "tree-sitter-elm"
version = "5.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95236155fa1cd5fcf92123e7e6aa7b6e8c6756b54b5d39afd792a23bd6c9eb7b"
version = "5.6.4"
source = "git+https://github.com/elm-tooling/tree-sitter-elm?rev=692c50c0b961364c40299e73c1306aecb5d20f40#692c50c0b961364c40299e73c1306aecb5d20f40"
dependencies = [
"cc",
"tree-sitter",
@ -9536,7 +9544,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.97.0"
version = "0.97.6"
dependencies = [
"activity_indicator",
"ai",
@ -9623,7 +9631,7 @@ dependencies = [
"tree-sitter",
"tree-sitter-bash",
"tree-sitter-c",
"tree-sitter-cpp",
"tree-sitter-cpp 0.20.0",
"tree-sitter-css",
"tree-sitter-elixir 0.1.0 (git+https://github.com/elixir-lang/tree-sitter-elixir?rev=4ba9dab6e2602960d95b2b625f3386c27e08084e)",
"tree-sitter-elm",

View file

@ -109,10 +109,10 @@ pretty_assertions = "1.3.0"
tree-sitter-bash = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "1b0321ee85701d5036c334a6f04761cdc672e64c" }
tree-sitter-c = "0.20.1"
tree-sitter-cpp = "0.20.0"
tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev="f44509141e7e483323d2ec178f2d2e6c0fc041c1" }
tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" }
tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "4ba9dab6e2602960d95b2b625f3386c27e08084e" }
tree-sitter-elm = "5.6.4"
tree-sitter-elm = { git = "https://github.com/elm-tooling/tree-sitter-elm", rev = "692c50c0b961364c40299e73c1306aecb5d20f40"}
tree-sitter-embedded-template = "0.20.0"
tree-sitter-glsl = { git = "https://github.com/theHamsta/tree-sitter-glsl", rev = "2a56fb7bc8bb03a1892b4741279dd0a8758b7fb3" }
tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" }

View file

@ -1637,6 +1637,7 @@ impl ConversationEditor {
let mut editor = Editor::for_buffer(conversation.read(cx).buffer.clone(), None, cx);
editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
editor.set_show_gutter(false, cx);
editor.set_show_wrap_guides(false, cx);
editor
});

View file

@ -89,7 +89,7 @@ use std::{
cmp::{self, Ordering, Reverse},
mem,
num::NonZeroU32,
ops::{ControlFlow, Deref, DerefMut, Range},
ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
path::Path,
sync::Arc,
time::{Duration, Instant},
@ -543,6 +543,7 @@ pub struct Editor {
show_local_selections: bool,
mode: EditorMode,
show_gutter: bool,
show_wrap_guides: Option<bool>,
placeholder_text: Option<Arc<str>>,
highlighted_rows: Option<Range<u32>>,
#[allow(clippy::type_complexity)]
@ -1375,6 +1376,7 @@ impl Editor {
show_local_selections: true,
mode,
show_gutter: mode == EditorMode::Full,
show_wrap_guides: None,
placeholder_text: None,
highlighted_rows: None,
background_highlights: Default::default(),
@ -1537,7 +1539,7 @@ impl Editor {
self.collapse_matches = collapse_matches;
}
fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
if self.collapse_matches {
return range.start..range.start;
}
@ -6374,8 +6376,8 @@ impl Editor {
.range
.to_offset(definition.target.buffer.read(cx));
let range = self.range_for_match(&range);
if Some(&definition.target.buffer) == self.buffer.read(cx).as_singleton().as_ref() {
let range = self.range_for_match(&range);
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range]);
});
@ -6392,7 +6394,6 @@ impl Editor {
// When selecting a definition in a different buffer, disable the nav history
// to avoid creating a history entry at the previous cursor location.
pane.update(cx, |pane, _| pane.disable_history());
let range = target_editor.range_for_match(&range);
target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range]);
});
@ -7188,6 +7189,10 @@ impl Editor {
pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
let mut wrap_guides = smallvec::smallvec![];
if self.show_wrap_guides == Some(false) {
return wrap_guides;
}
let settings = self.buffer.read(cx).settings_at(0, cx);
if settings.show_wrap_guides {
if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
@ -7245,6 +7250,11 @@ impl Editor {
cx.notify();
}
pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
self.show_wrap_guides = Some(show_gutter);
cx.notify();
}
pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
@ -7433,6 +7443,78 @@ impl Editor {
results
}
pub fn background_highlight_row_ranges<T: 'static>(
&self,
search_range: Range<Anchor>,
display_snapshot: &DisplaySnapshot,
count: usize,
) -> Vec<RangeInclusive<DisplayPoint>> {
let mut results = Vec::new();
let buffer = &display_snapshot.buffer_snapshot;
let Some((_, ranges)) = self.background_highlights
.get(&TypeId::of::<T>()) else {
return vec![];
};
let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&search_range.start, buffer);
if cmp.is_gt() {
Ordering::Greater
} else {
Ordering::Less
}
}) {
Ok(i) | Err(i) => i,
};
let mut push_region = |start: Option<Point>, end: Option<Point>| {
if let (Some(start_display), Some(end_display)) = (start, end) {
results.push(
start_display.to_display_point(display_snapshot)
..=end_display.to_display_point(display_snapshot),
);
}
};
let mut start_row: Option<Point> = None;
let mut end_row: Option<Point> = None;
if ranges.len() > count {
return vec![];
}
for range in &ranges[start_ix..] {
if range.start.cmp(&search_range.end, buffer).is_ge() {
break;
}
let end = range.end.to_point(buffer);
if let Some(current_row) = &end_row {
if end.row == current_row.row {
continue;
}
}
let start = range.start.to_point(buffer);
if start_row.is_none() {
assert_eq!(end_row, None);
start_row = Some(start);
end_row = Some(end);
continue;
}
if let Some(current_end) = end_row.as_mut() {
if start.row > current_end.row + 1 {
push_region(start_row, end_row);
start_row = Some(start);
end_row = Some(end);
} else {
// Merge two hunks.
*current_end = end;
}
} else {
unreachable!();
}
}
// We might still have a hunk that was not rendered (if there was a search hit on the last line)
push_region(start_row, end_row);
results
}
pub fn highlight_text<T: 'static>(
&mut self,
ranges: Vec<Range<Anchor>>,

View file

@ -172,6 +172,10 @@ impl EditorElement {
.on_drag(MouseButton::Left, {
let position_map = position_map.clone();
move |event, editor, cx| {
if event.end {
return;
}
if !Self::mouse_dragged(
editor,
event.platform_event,
@ -542,8 +546,20 @@ impl EditorElement {
});
}
let scroll_left =
layout.position_map.snapshot.scroll_position().x() * layout.position_map.em_width;
for (wrap_position, active) in layout.wrap_guides.iter() {
let x = text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.;
let x =
(text_bounds.origin_x() + wrap_position + layout.position_map.em_width / 2.)
- scroll_left;
if x < text_bounds.origin_x()
|| (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
{
continue;
}
let color = if *active {
self.style.active_wrap_guide
} else {
@ -1032,6 +1048,10 @@ impl EditorElement {
scene.pop_layer();
}
fn scrollbar_left(&self, bounds: &RectF) -> f32 {
bounds.max_x() - self.style.theme.scrollbar.width
}
fn paint_scrollbar(
&mut self,
scene: &mut SceneBuilder,
@ -1050,7 +1070,7 @@ impl EditorElement {
let top = bounds.min_y();
let bottom = bounds.max_y();
let right = bounds.max_x();
let left = right - style.width;
let left = self.scrollbar_left(&bounds);
let row_range = &layout.scrollbar_row_range;
let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
@ -1087,8 +1107,6 @@ impl EditorElement {
if layout.is_singleton && scrollbar_settings.selections {
let start_anchor = Anchor::min();
let end_anchor = Anchor::max();
let mut start_row = None;
let mut end_row = None;
let color = scrollbar_theme.selections;
let border = Border {
width: 1.,
@ -1099,54 +1117,32 @@ impl EditorElement {
bottom: false,
left: true,
};
let mut push_region = |start, end| {
if let (Some(start_display), Some(end_display)) = (start, end) {
let start_y = y_for_row(start_display as f32);
let mut end_y = y_for_row(end_display as f32);
if end_y - start_y < 1. {
end_y = start_y + 1.;
}
let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
scene.push_quad(Quad {
bounds,
background: Some(color),
border,
corner_radius: style.thumb.corner_radius,
})
let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
let start_y = y_for_row(start.row() as f32);
let mut end_y = y_for_row(end.row() as f32);
if end_y - start_y < 1. {
end_y = start_y + 1.;
}
let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
scene.push_quad(Quad {
bounds,
background: Some(color),
border,
corner_radius: style.thumb.corner_radius,
})
};
for (row, _) in &editor
.background_highlights_in_range_for::<crate::items::BufferSearchHighlights>(
let background_ranges = editor
.background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
start_anchor..end_anchor,
&layout.position_map.snapshot,
&theme,
)
{
let start_display = row.start;
let end_display = row.end;
if start_row.is_none() {
assert_eq!(end_row, None);
start_row = Some(start_display.row());
end_row = Some(end_display.row());
continue;
}
if let Some(current_end) = end_row.as_mut() {
if start_display.row() > *current_end + 1 {
push_region(start_row, end_row);
start_row = Some(start_display.row());
end_row = Some(end_display.row());
} else {
// Merge two hunks.
*current_end = end_display.row();
}
} else {
unreachable!();
}
50000,
);
for row in background_ranges {
let start = row.start();
let end = row.end();
push_region(*start, *end);
}
// We might still have a hunk that was not rendered (if there was a search hit on the last line)
push_region(start_row, end_row);
}
if layout.is_singleton && scrollbar_settings.git_diff {
@ -1235,6 +1231,10 @@ impl EditorElement {
})
.on_drag(MouseButton::Left, {
move |event, editor: &mut Editor, cx| {
if event.end {
return;
}
let y = event.prev_mouse_position.y();
let new_y = event.position.y();
if thumb_top < y && y < thumb_bottom {

View file

@ -147,6 +147,9 @@ impl<V: View> Element<V> for Resizable<V> {
let max_size = side.relevant_component(constraint.max);
let on_resize = self.on_resize.clone();
move |event, view: &mut V, cx| {
if event.end {
return;
}
let new_size = min_size
.max(prev_size + side.compute_delta(event))
.min(max_size)

View file

@ -182,8 +182,8 @@ impl CachedLspAdapter {
self.adapter.workspace_configuration(cx)
}
pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
self.adapter.process_diagnostics(params).await
pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
self.adapter.process_diagnostics(params)
}
pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) {
@ -262,7 +262,7 @@ pub trait LspAdapter: 'static + Send + Sync {
container_dir: PathBuf,
) -> Option<LanguageServerBinary>;
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
@ -844,8 +844,8 @@ impl LanguageRegistry {
}
}
}
Err(err) => {
log::error!("failed to load language {name} - {err}");
Err(e) => {
log::error!("failed to load language {name}:\n{:?}", e);
let mut state = this.state.write();
state.mark_language_loaded(id);
if let Some(mut txs) = state.loading_languages.remove(&id) {
@ -853,7 +853,7 @@ impl LanguageRegistry {
let _ = tx.send(Err(anyhow!(
"failed to load language {}: {}",
name,
err
e
)));
}
}
@ -1188,25 +1188,39 @@ impl Language {
pub fn with_queries(mut self, queries: LanguageQueries) -> Result<Self> {
if let Some(query) = queries.highlights {
self = self.with_highlights_query(query.as_ref())?;
self = self
.with_highlights_query(query.as_ref())
.context("Error loading highlights query")?;
}
if let Some(query) = queries.brackets {
self = self.with_brackets_query(query.as_ref())?;
self = self
.with_brackets_query(query.as_ref())
.context("Error loading brackets query")?;
}
if let Some(query) = queries.indents {
self = self.with_indents_query(query.as_ref())?;
self = self
.with_indents_query(query.as_ref())
.context("Error loading indents query")?;
}
if let Some(query) = queries.outline {
self = self.with_outline_query(query.as_ref())?;
self = self
.with_outline_query(query.as_ref())
.context("Error loading outline query")?;
}
if let Some(query) = queries.embedding {
self = self.with_embedding_query(query.as_ref())?;
self = self
.with_embedding_query(query.as_ref())
.context("Error loading embedding query")?;
}
if let Some(query) = queries.injections {
self = self.with_injection_query(query.as_ref())?;
self = self
.with_injection_query(query.as_ref())
.context("Error loading injection query")?;
}
if let Some(query) = queries.overrides {
self = self.with_override_query(query.as_ref())?;
self = self
.with_override_query(query.as_ref())
.context("Error loading override query")?;
}
Ok(self)
}
@ -1473,12 +1487,6 @@ impl Language {
None
}
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
for adapter in &self.adapters {
adapter.process_diagnostics(diagnostics).await;
}
}
pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
for adapter in &self.adapters {
adapter.process_completion(completion).await;
@ -1742,7 +1750,7 @@ impl LspAdapter for Arc<FakeLspAdapter> {
unreachable!();
}
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
self.disk_based_diagnostics_sources.clone()

View file

@ -2769,24 +2769,21 @@ impl Project {
language_server
.on_notification::<lsp::notification::PublishDiagnostics, _>({
let adapter = adapter.clone();
move |mut params, cx| {
move |mut params, mut cx| {
let this = this;
let adapter = adapter.clone();
cx.spawn(|mut cx| async move {
adapter.process_diagnostics(&mut params).await;
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.update_diagnostics(
server_id,
params,
&adapter.disk_based_diagnostic_sources,
cx,
)
.log_err();
});
}
})
.detach();
adapter.process_diagnostics(&mut params);
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.update_diagnostics(
server_id,
params,
&adapter.disk_based_diagnostic_sources,
cx,
)
.log_err();
});
}
}
})
.detach();

View file

@ -783,6 +783,7 @@ impl ProjectSearchView {
let range_to_select = match_ranges[new_index].clone();
self.results_editor.update(cx, |editor, cx| {
let range_to_select = editor.range_for_match(&range_to_select);
editor.unfold_ranges([range_to_select.clone()], false, true, cx);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range_to_select])
@ -824,8 +825,12 @@ impl ProjectSearchView {
let is_new_search = self.search_id != prev_search_id;
self.results_editor.update(cx, |editor, cx| {
if is_new_search {
let range_to_select = match_ranges
.first()
.clone()
.map(|range| editor.range_for_match(range));
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges(match_ranges.first().cloned())
s.select_ranges(range_to_select)
});
}
editor.highlight_background::<Self>(

View file

@ -438,6 +438,7 @@ where
} => {
if ascending {
entry.index += 1;
entry.position = self.position.clone();
}
for (child_tree, child_summary) in child_trees[entry.index..]

View file

@ -738,7 +738,7 @@ mod tests {
for _ in 0..num_operations {
let splice_end = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let splice_start = rng.gen_range(0..splice_end + 1);
let count = rng.gen_range(0..3);
let count = rng.gen_range(0..10);
let tree_end = tree.extent::<Count>(&());
let new_items = rng
.sample_iter(distributions::Standard)
@ -805,10 +805,12 @@ mod tests {
}
assert_eq!(filter_cursor.item(), None);
let mut pos = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
let mut before_start = false;
let mut cursor = tree.cursor::<Count>();
cursor.seek(&Count(pos), Bias::Right, &());
let start_pos = rng.gen_range(0..=reference_items.len());
cursor.seek(&Count(start_pos), Bias::Right, &());
let mut pos = rng.gen_range(start_pos..=reference_items.len());
cursor.seek_forward(&Count(pos), Bias::Right, &());
for i in 0..10 {
assert_eq!(cursor.start().0, pos);

View file

@ -78,7 +78,7 @@ lazy_static! {
// * use more strict regex for `file://` protocol matching: original regex has `file:` inside, but we want to avoid matching `some::file::module` strings.
static ref URL_REGEX: RegexSearch = RegexSearch::new(r#"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file://|git://|ssh:|ftp://)[^\u{0000}-\u{001F}\u{007F}-\u{009F}<>"\s{-}\^⟨⟩`]+"#).unwrap();
static ref WORD_REGEX: RegexSearch = RegexSearch::new("[\\w.:/@-~]+").unwrap();
static ref WORD_REGEX: RegexSearch = RegexSearch::new(r#"[\w.:/@\-~]+"#).unwrap();
}
///Upward flowing events, for changing the title and such

View file

@ -411,6 +411,10 @@ impl TerminalElement {
})
// Update drag selections
.on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| {
if event.end {
return;
}
if cx.is_self_focused() {
if let Some(conn_handle) = connection.upgrade(cx) {
conn_handle.update(cx, |terminal, cx| {

View file

@ -1,20 +1,64 @@
use gpui::{elements::Label, AnyElement, Element, Entity, View, ViewContext};
use gpui::{
elements::{Empty, Label},
AnyElement, Element, Entity, Subscription, View, ViewContext,
};
use settings::SettingsStore;
use workspace::{item::ItemHandle, StatusItemView};
use crate::state::Mode;
use crate::{state::Mode, Vim, VimEvent, VimModeSetting};
pub struct ModeIndicator {
pub mode: Mode,
pub mode: Option<Mode>,
_subscription: Subscription,
}
impl ModeIndicator {
pub fn new(mode: Mode) -> Self {
Self { mode }
pub fn new(cx: &mut ViewContext<Self>) -> Self {
let handle = cx.handle().downgrade();
let _subscription = cx.subscribe_global::<VimEvent, _>(move |&event, cx| {
if let Some(mode_indicator) = handle.upgrade(cx) {
match event {
VimEvent::ModeChanged { mode } => {
cx.update_window(mode_indicator.window_id(), |cx| {
mode_indicator.update(cx, move |mode_indicator, cx| {
mode_indicator.set_mode(mode, cx);
})
});
}
}
}
});
cx.observe_global::<SettingsStore, _>(move |mode_indicator, cx| {
if settings::get::<VimModeSetting>(cx).0 {
mode_indicator.mode = cx
.has_global::<Vim>()
.then(|| cx.global::<Vim>().state.mode);
} else {
mode_indicator.mode.take();
}
})
.detach();
// Vim doesn't exist in some tests
let mode = cx
.has_global::<Vim>()
.then(|| {
let vim = cx.global::<Vim>();
vim.enabled.then(|| vim.state.mode)
})
.flatten();
Self {
mode,
_subscription,
}
}
pub fn set_mode(&mut self, mode: Mode, cx: &mut ViewContext<Self>) {
if mode != self.mode {
self.mode = mode;
if self.mode != Some(mode) {
self.mode = Some(mode);
cx.notify();
}
}
@ -30,11 +74,16 @@ impl View for ModeIndicator {
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
let Some(mode) = self.mode.as_ref() else {
return Empty::new().into_any();
};
let theme = &theme::current(cx).workspace.status_bar;
// we always choose text to be 12 monospace characters
// so that as the mode indicator changes, the rest of the
// UI stays still.
let text = match self.mode {
let text = match mode {
Mode::Normal => "-- NORMAL --",
Mode::Insert => "-- INSERT --",
Mode::Visual { line: false } => "-- VISUAL --",

View file

@ -215,7 +215,7 @@ async fn test_status_indicator(
assert_eq!(
cx.workspace(|_, cx| mode_indicator.read(cx).mode),
Mode::Normal
Some(Mode::Normal)
);
// shows the correct mode
@ -223,7 +223,7 @@ async fn test_status_indicator(
deterministic.run_until_parked();
assert_eq!(
cx.workspace(|_, cx| mode_indicator.read(cx).mode),
Mode::Insert
Some(Mode::Insert)
);
// shows even in search
@ -231,7 +231,7 @@ async fn test_status_indicator(
deterministic.run_until_parked();
assert_eq!(
cx.workspace(|_, cx| mode_indicator.read(cx).mode),
Mode::Visual { line: false }
Some(Mode::Visual { line: false })
);
// hides if vim mode is disabled
@ -239,15 +239,15 @@ async fn test_status_indicator(
deterministic.run_until_parked();
cx.workspace(|workspace, cx| {
let status_bar = workspace.status_bar().read(cx);
let mode_indicator = status_bar.item_of_type::<ModeIndicator>();
assert!(mode_indicator.is_none());
let mode_indicator = status_bar.item_of_type::<ModeIndicator>().unwrap();
assert!(mode_indicator.read(cx).mode.is_none());
});
cx.enable_vim();
deterministic.run_until_parked();
cx.workspace(|workspace, cx| {
let status_bar = workspace.status_bar().read(cx);
let mode_indicator = status_bar.item_of_type::<ModeIndicator>();
assert!(mode_indicator.is_some());
let mode_indicator = status_bar.item_of_type::<ModeIndicator>().unwrap();
assert!(mode_indicator.read(cx).mode.is_some());
});
}

View file

@ -43,6 +43,10 @@ impl<'a> VimTestContext<'a> {
toolbar.add_item(project_search_bar, cx);
})
});
workspace.status_bar().update(cx, |status_bar, cx| {
let vim_mode_indicator = cx.add_view(ModeIndicator::new);
status_bar.add_right_item(vim_mode_indicator, cx);
});
});
Self { cx }

View file

@ -43,6 +43,11 @@ struct Number(u8);
actions!(vim, [Tab, Enter]);
impl_actions!(vim, [Number, SwitchMode, PushOperator]);
#[derive(Copy, Clone, Debug)]
enum VimEvent {
ModeChanged { mode: Mode },
}
pub fn init(cx: &mut AppContext) {
settings::register::<VimModeSetting>(cx);
@ -121,8 +126,6 @@ pub fn observe_keystrokes(cx: &mut WindowContext) {
pub struct Vim {
active_editor: Option<WeakViewHandle<Editor>>,
editor_subscription: Option<Subscription>,
mode_indicator: Option<ViewHandle<ModeIndicator>>,
enabled: bool,
state: VimState,
}
@ -181,9 +184,7 @@ impl Vim {
self.state.mode = mode;
self.state.operator_stack.clear();
if let Some(mode_indicator) = &self.mode_indicator {
mode_indicator.update(cx, |mode_indicator, cx| mode_indicator.set_mode(mode, cx))
}
cx.emit_global(VimEvent::ModeChanged { mode });
// Sync editor settings like clip mode
self.sync_vim_settings(cx);
@ -271,44 +272,6 @@ impl Vim {
}
}
fn sync_mode_indicator(cx: &mut WindowContext) {
let Some(workspace) = cx.root_view()
.downcast_ref::<Workspace>()
.map(|workspace| workspace.downgrade()) else {
return;
};
cx.spawn(|mut cx| async move {
workspace.update(&mut cx, |workspace, cx| {
Vim::update(cx, |vim, cx| {
workspace.status_bar().update(cx, |status_bar, cx| {
let current_position = status_bar.position_of_item::<ModeIndicator>();
if vim.enabled && current_position.is_none() {
if vim.mode_indicator.is_none() {
vim.mode_indicator =
Some(cx.add_view(|_| ModeIndicator::new(vim.state.mode)));
};
let mode_indicator = vim.mode_indicator.as_ref().unwrap();
let position = status_bar
.position_of_item::<language_selector::ActiveBufferLanguage>();
if let Some(position) = position {
status_bar.insert_item_after(position, mode_indicator.clone(), cx)
} else {
status_bar.add_left_item(mode_indicator.clone(), cx)
}
} else if !vim.enabled {
if let Some(position) = current_position {
status_bar.remove_item_at(position, cx)
}
}
})
})
})
})
.detach_and_log_err(cx);
}
fn set_enabled(&mut self, enabled: bool, cx: &mut AppContext) {
if self.enabled != enabled {
self.enabled = enabled;
@ -359,8 +322,6 @@ impl Vim {
self.unhook_vim_settings(editor, cx);
}
});
Vim::sync_mode_indicator(cx);
}
fn unhook_vim_settings(&self, editor: &mut Editor, cx: &mut ViewContext<Editor>) {

View file

@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.97.0"
version = "0.97.6"
publish = false
[lib]

View file

@ -1 +1 @@
dev
stable

View file

@ -102,7 +102,7 @@ impl LspAdapter for RustLspAdapter {
Some("rust-analyzer/flycheck".into())
}
async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
lazy_static! {
static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();
}
@ -310,7 +310,7 @@ mod tests {
},
],
};
RustLspAdapter.process_diagnostics(&mut params).await;
RustLspAdapter.process_diagnostics(&mut params);
assert_eq!(params.diagnostics[0].message, "use of moved value `a`");

View file

@ -308,6 +308,7 @@ pub fn initialize_workspace(
);
let active_buffer_language =
cx.add_view(|_| language_selector::ActiveBufferLanguage::new(workspace));
let vim_mode_indicator = cx.add_view(|cx| vim::ModeIndicator::new(cx));
let feedback_button = cx.add_view(|_| {
feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace)
});
@ -319,6 +320,7 @@ pub fn initialize_workspace(
status_bar.add_right_item(feedback_button, cx);
status_bar.add_right_item(copilot, cx);
status_bar.add_right_item(active_buffer_language, cx);
status_bar.add_right_item(vim_mode_indicator, cx);
status_bar.add_right_item(cursor_position, cx);
});

View file

@ -170,8 +170,8 @@ export default function editor(): any {
line_number: with_opacity(foreground(layer), 0.35),
line_number_active: foreground(layer),
rename_fade: 0.6,
wrap_guide: with_opacity(foreground(layer), 0.1),
active_wrap_guide: with_opacity(foreground(layer), 0.2),
wrap_guide: with_opacity(foreground(layer), 0.05),
active_wrap_guide: with_opacity(foreground(layer), 0.1),
unnecessary_code_fade: 0.5,
selection: theme.players[0],
whitespace: theme.ramps.neutral(0.5).hex(),