Compare commits
23 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1c67a5025 | ||
![]() |
cbaf7cc972 | ||
![]() |
c24c4063e3 | ||
![]() |
707da9bbbf | ||
![]() |
c826010008 | ||
![]() |
e928e1db4e | ||
![]() |
f5b1962b0e | ||
![]() |
0b13c6bc84 | ||
![]() |
75365249cc | ||
![]() |
1c2f5162bc | ||
![]() |
209c68c85e | ||
![]() |
023a617b30 | ||
![]() |
286d302273 | ||
![]() |
4091a2004e | ||
![]() |
9d4a2bfb58 | ||
![]() |
33e58d47ac | ||
![]() |
056282f59b | ||
![]() |
553b9601d1 | ||
![]() |
a166f0b56a | ||
![]() |
badc2ec0e9 | ||
![]() |
9c3c719ce0 | ||
![]() |
3594b5e2a8 | ||
![]() |
99d0ed4a76 |
23 changed files with 306 additions and 170 deletions
13
.github/workflows/release_actions.yml
vendored
13
.github/workflows/release_actions.yml
vendored
|
@ -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
24
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
|
@ -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>>,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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..]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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 --",
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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>) {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -1 +1 @@
|
|||
dev
|
||||
stable
|
|
@ -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`");
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue