Detailed changes
@@ -23,6 +23,7 @@
"c++": "cpp",
"cc": "cpp",
"cjs": "javascript",
+ "cjsx": "react",
"coffee": "coffeescript",
"conf": "settings",
"cpp": "cpp",
@@ -30,6 +31,7 @@
"csv": "storage",
"cxx": "cpp",
"cts": "typescript",
+ "ctsx": "react",
"dart": "dart",
"dat": "storage",
"db": "storage",
@@ -121,6 +123,7 @@
"metadata": "code",
"metal": "metal",
"mjs": "javascript",
+ "mjsx": "react",
"mka": "audio",
"mkv": "video",
"ml": "ocaml",
@@ -130,6 +133,7 @@
"mp3": "audio",
"mp4": "video",
"mts": "typescript",
+ "mtsx": "react",
"myd": "storage",
"myi": "storage",
"nim": "nim",
@@ -186,6 +190,17 @@
"sh": "terminal",
"sql": "storage",
"sqlite": "storage",
+ "stylelint.config.cjs": "stylelint",
+ "stylelint.config.js": "stylelint",
+ "stylelint.config.mjs": "stylelint",
+ "stylelintignore": "stylelint",
+ "stylelintrc": "stylelint",
+ "stylelintrc.cjs": "stylelint",
+ "stylelintrc.js": "stylelint",
+ "stylelintrc.json": "stylelint",
+ "stylelintrc.mjs": "stylelint",
+ "stylelintrc.yaml": "stylelint",
+ "stylelintrc.yml": "stylelint",
"svelte": "svelte",
"svg": "image",
"swift": "swift",
@@ -587,18 +587,16 @@ impl BufferDiff {
range: Range<Anchor>,
buffer: &text::BufferSnapshot,
cx: &App,
- ) -> Option<Range<Anchor>> {
+ ) -> Range<Anchor> {
let start = self
.hunks_intersecting_range(range.clone(), &buffer, cx)
- .next()?
- .buffer_range
- .start;
+ .next()
+ .map_or(Anchor::MIN, |hunk| hunk.buffer_range.start);
let end = self
.hunks_intersecting_range_rev(range.clone(), &buffer)
- .next()?
- .buffer_range
- .end;
- Some(start..end)
+ .next()
+ .map_or(Anchor::MAX, |hunk| hunk.buffer_range.end);
+ start..end
}
#[allow(clippy::too_many_arguments)]
@@ -265,6 +265,8 @@ gpui::actions!(
Copy,
CopyFileLocation,
CopyHighlightJson,
+ CopyFileName,
+ CopyFileNameWithoutExtension,
CopyPath,
CopyPermalinkToLine,
CopyRelativePath,
@@ -5457,19 +5457,27 @@ impl Editor {
};
if &accept_keystroke.modifiers == modifiers {
- if let Some(completion) = self.active_inline_completion.as_ref() {
- if self.edit_prediction_preview.start(
- &completion.completion,
- &position_map.snapshot,
- self.selections
- .newest_anchor()
- .head()
- .to_display_point(&position_map.snapshot),
- ) {
- self.request_autoscroll(Autoscroll::fit(), cx);
- self.update_visible_inline_completion(window, cx);
- cx.notify();
- }
+ let Some(completion) = self.active_inline_completion.as_ref() else {
+ return;
+ };
+
+ if !self.edit_prediction_requires_modifier() && !self.has_visible_completions_menu() {
+ return;
+ }
+
+ let transitioned = self.edit_prediction_preview.start(
+ &completion.completion,
+ &position_map.snapshot,
+ self.selections
+ .newest_anchor()
+ .head()
+ .to_display_point(&position_map.snapshot),
+ );
+
+ if transitioned {
+ self.request_autoscroll(Autoscroll::fit(), cx);
+ self.update_visible_inline_completion(window, cx);
+ cx.notify();
}
} else if self.edit_prediction_preview.end(
self.selections
@@ -13116,6 +13124,31 @@ impl Editor {
}
}
+ pub fn copy_file_name_without_extension(
+ &mut self,
+ _: &CopyFileNameWithoutExtension,
+ _: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if let Some(file) = self.target_file(cx) {
+ if let Some(file_stem) = file.path().file_stem() {
+ if let Some(name) = file_stem.to_str() {
+ cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
+ }
+ }
+ }
+ }
+
+ pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
+ if let Some(file) = self.target_file(cx) {
+ if let Some(file_name) = file.path().file_name() {
+ if let Some(name) = file_name.to_str() {
+ cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
+ }
+ }
+ }
+ }
+
pub fn toggle_git_blame(
&mut self,
_: &ToggleGitBlame,
@@ -5362,6 +5362,21 @@ async fn test_select_previous_with_single_caret(cx: &mut gpui::TestAppContext) {
cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndef«abcˇ»\n«abcˇ»");
}
+#[gpui::test]
+async fn test_select_previous_empty_buffer(cx: &mut gpui::TestAppContext) {
+ init_test(cx, |_| {});
+
+ let mut cx = EditorTestContext::new(cx).await;
+ cx.set_state("aˇ");
+
+ cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx))
+ .unwrap();
+ cx.assert_editor_state("«aˇ»");
+ cx.update_editor(|e, window, cx| e.select_previous(&SelectPrevious::default(), window, cx))
+ .unwrap();
+ cx.assert_editor_state("«aˇ»");
+}
+
#[gpui::test]
async fn test_select_previous_with_multiple_carets(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
@@ -408,6 +408,8 @@ impl EditorElement {
register_action(editor, window, Editor::reveal_in_finder);
register_action(editor, window, Editor::copy_path);
register_action(editor, window, Editor::copy_relative_path);
+ register_action(editor, window, Editor::copy_file_name);
+ register_action(editor, window, Editor::copy_file_name_without_extension);
register_action(editor, window, Editor::copy_highlight_json);
register_action(editor, window, Editor::copy_permalink_to_line);
register_action(editor, window, Editor::open_permalink_to_line);
@@ -3628,6 +3630,16 @@ impl EditorElement {
return None;
}
+ // Adjust text origin for horizontal scrolling (in some cases here)
+ let start_point =
+ text_bounds.origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
+
+ // Clamp left offset after extreme scrollings
+ let clamp_start = |point: gpui::Point<Pixels>| gpui::Point {
+ x: point.x.max(text_bounds.origin.x),
+ y: point.y,
+ };
+
match &active_inline_completion.completion {
InlineCompletion::Move { target, .. } => {
if editor.edit_prediction_requires_modifier() {
@@ -3684,6 +3696,7 @@ impl EditorElement {
)?;
let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
let offset = point((text_bounds.size.width - size.width) / 2., PADDING_Y);
+
element.prepaint_at(text_bounds.origin + offset, window, cx);
Some(element)
} else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
@@ -3699,6 +3712,7 @@ impl EditorElement {
(text_bounds.size.width - size.width) / 2.,
text_bounds.size.height - size.height - PADDING_Y,
);
+
element.prepaint_at(text_bounds.origin + offset, window, cx);
Some(element)
} else {
@@ -3709,7 +3723,6 @@ impl EditorElement {
window,
cx,
)?;
-
let target_line_end = DisplayPoint::new(
target_display_point.row(),
editor_snapshot.line_len(target_display_point.row()),
@@ -3717,8 +3730,9 @@ impl EditorElement {
let origin = self.editor.update(cx, |editor, _cx| {
editor.display_to_pixel_point(target_line_end, editor_snapshot, window)
})?;
+
element.prepaint_as_root(
- text_bounds.origin + origin + point(PADDING_X, px(0.)),
+ clamp_start(start_point + origin + point(PADDING_X, px(0.))),
AvailableSpace::min_size(),
window,
cx,
@@ -3778,12 +3792,11 @@ impl EditorElement {
})?;
element.prepaint_as_root(
- text_bounds.origin + origin + point(PADDING_X, px(0.)),
+ clamp_start(start_point + origin + point(PADDING_X, px(0.))),
AvailableSpace::min_size(),
window,
cx,
);
-
return Some(element);
}
EditDisplayMode::Inline => return None,
@@ -1102,6 +1102,10 @@ impl Buffer {
let mut syntax_snapshot = self.syntax_map.lock().snapshot();
cx.background_executor().spawn(async move {
if !edits.is_empty() {
+ if let Some(language) = language.clone() {
+ syntax_snapshot.reparse(&old_snapshot, registry.clone(), language);
+ }
+
branch_buffer.edit(edits.iter().cloned());
let snapshot = branch_buffer.snapshot();
syntax_snapshot.interpolate(&snapshot);
@@ -7121,7 +7121,7 @@ impl<'a> Iterator for ReversedMultiBufferChunks<'a> {
self.offset -= 1;
Some("\n")
} else {
- let chunk = self.current_chunks.as_mut().unwrap().next().unwrap();
+ let chunk = self.current_chunks.as_mut().unwrap().next()?;
self.offset -= chunk.len();
Some(chunk)
}
@@ -260,15 +260,12 @@ impl BufferDiffState {
let changed_range = match (unstaged_changed_range, uncommitted_changed_range) {
(None, None) => None,
(Some(unstaged_range), None) => {
- uncommitted_diff.range_to_hunk_range(unstaged_range, &buffer, cx)
+ Some(uncommitted_diff.range_to_hunk_range(unstaged_range, &buffer, cx))
}
(None, Some(uncommitted_range)) => Some(uncommitted_range),
(Some(unstaged_range), Some(uncommitted_range)) => maybe!({
- let expanded_range = uncommitted_diff.range_to_hunk_range(
- unstaged_range,
- &buffer,
- cx,
- )?;
+ let expanded_range =
+ uncommitted_diff.range_to_hunk_range(unstaged_range, &buffer, cx);
let start = expanded_range.start.min(&uncommitted_range.start, &buffer);
let end = expanded_range.end.max(&uncommitted_range.end, &buffer);
Some(start..end)
@@ -113,6 +113,7 @@ const FILE_ICONS: &[(&str, &str)] = &[
("scala", "icons/file_icons/scala.svg"),
("settings", "icons/file_icons/settings.svg"),
("storage", "icons/file_icons/database.svg"),
+ ("stylelint", "icons/file_icons/javascript.svg"),
("svelte", "icons/file_icons/html.svg"),
("swift", "icons/file_icons/swift.svg"),
("tcl", "icons/file_icons/tcl.svg"),
@@ -664,11 +664,17 @@ and then another
let mut did_retry = false;
loop {
- let request_builder = http_client::Request::builder().method(Method::POST).uri(
- http_client
- .build_zed_llm_url("/predict_edits/v2", &[])?
- .as_ref(),
- );
+ let request_builder = http_client::Request::builder().method(Method::POST);
+ let request_builder =
+ if let Ok(predict_edits_url) = std::env::var("ZED_PREDICT_EDITS_URL") {
+ request_builder.uri(predict_edits_url)
+ } else {
+ request_builder.uri(
+ http_client
+ .build_zed_llm_url("/predict_edits/v2", &[])?
+ .as_ref(),
+ )
+ };
let request = request_builder
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", token))