Compare commits

..

3 Commits

Author SHA1 Message Date
Ben Kunkle
6418b05a4f clippy
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 11:15:48 -04:00
Ben Kunkle
cdaacd4803 clean
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 10:55:26 -04:00
Ben Kunkle
53fab9730b improve behavior of code_actions_on_format migration
Co-Authored-By: Cole <cole@zed.dev>
2025-10-16 10:53:30 -04:00
19 changed files with 219 additions and 244 deletions

View File

@@ -47,13 +47,13 @@ pub struct PredictEditsRequest {
pub enum PromptFormat {
MarkedExcerpt,
LabeledSections,
NumLinesUniDiff,
NumberedLines,
/// Prompt format intended for use via zeta_cli
OnlySnippets,
}
impl PromptFormat {
pub const DEFAULT: PromptFormat = PromptFormat::NumLinesUniDiff;
pub const DEFAULT: PromptFormat = PromptFormat::NumberedLines;
}
impl Default for PromptFormat {
@@ -74,7 +74,7 @@ impl std::fmt::Display for PromptFormat {
PromptFormat::MarkedExcerpt => write!(f, "Marked Excerpt"),
PromptFormat::LabeledSections => write!(f, "Labeled Sections"),
PromptFormat::OnlySnippets => write!(f, "Only Snippets"),
PromptFormat::NumLinesUniDiff => write!(f, "Numbered Lines / Unified Diff"),
PromptFormat::NumberedLines => write!(f, "Numbered Lines"),
}
}
}

View File

@@ -15,30 +15,27 @@ use strum::{EnumIter, IntoEnumIterator};
pub const DEFAULT_MAX_PROMPT_BYTES: usize = 10 * 1024;
pub const CURSOR_MARKER: &str = "<|user_cursor|>";
pub const CURSOR_MARKER: &str = "<|cursor_position|>";
/// NOTE: Differs from zed version of constant - includes a newline
pub const EDITABLE_REGION_START_MARKER_WITH_NEWLINE: &str = "<|editable_region_start|>\n";
/// NOTE: Differs from zed version of constant - includes a newline
pub const EDITABLE_REGION_END_MARKER_WITH_NEWLINE: &str = "<|editable_region_end|>\n";
// TODO: use constants for markers?
const MARKED_EXCERPT_INSTRUCTIONS: &str = indoc! {"
const MARKED_EXCERPT_SYSTEM_PROMPT: &str = indoc! {"
You are a code completion assistant and your task is to analyze user edits and then rewrite an excerpt that the user provides, suggesting the appropriate edits within the excerpt, taking into account the cursor location.
The excerpt to edit will be wrapped in markers <|editable_region_start|> and <|editable_region_end|>. The cursor position is marked with <|user_cursor|>. Please respond with edited code for that region.
The excerpt to edit will be wrapped in markers <|editable_region_start|> and <|editable_region_end|>. The cursor position is marked with <|cursor_position|>. Please respond with edited code for that region.
Other code is provided for context, and `…` indicates when code has been skipped.
# Edit History:
"};
const LABELED_SECTIONS_INSTRUCTIONS: &str = indoc! {r#"
const LABELED_SECTIONS_SYSTEM_PROMPT: &str = indoc! {r#"
You are a code completion assistant and your task is to analyze user edits, and suggest an edit to one of the provided sections of code.
Sections of code are grouped by file and then labeled by `<|section_N|>` (e.g `<|section_8|>`).
The cursor position is marked with `<|user_cursor|>` and it will appear within a special section labeled `<|current_section|>`. Prefer editing the current section until no more changes are needed within it.
The cursor position is marked with `<|cursor_position|>` and it will appear within a special section labeled `<|current_section|>`. Prefer editing the current section until no more changes are needed within it.
Respond ONLY with the name of the section to edit on a single line, followed by all of the code that should replace that section. For example:
@@ -46,12 +43,9 @@ const LABELED_SECTIONS_INSTRUCTIONS: &str = indoc! {r#"
for i in 0..16 {
println!("{i}");
}
# Edit History:
"#};
const NUMBERED_LINES_INSTRUCTIONS: &str = indoc! {r#"
const NUMBERED_LINES_SYSTEM_PROMPT: &str = indoc! {r#"
# Instructions
You are a code completion assistant helping a programmer finish their work. Your task is to:
@@ -77,27 +71,16 @@ const NUMBERED_LINES_INSTRUCTIONS: &str = indoc! {r#"
# Example output:
```
--- a/src/myapp/cli.py
+++ b/src/myapp/cli.py
--- a/distill-claude/tmp-outs/edits_history.txt
+++ b/distill-claude/tmp-outs/edits_history.txt
@@ -1,3 +1,3 @@
-
-
-import sys
+import json
```
# Edit History:
"#};
const UNIFIED_DIFF_REMINDER: &str = indoc! {"
---
Please analyze the edit history and the files, then provide the unified diff for your predicted edits.
Do not include the cursor marker in your output.
If you're editing multiple files, be sure to reflect filename in the hunk's header.
"};
pub struct PlannedPrompt<'a> {
request: &'a predict_edits_v3::PredictEditsRequest,
/// Snippets to include in the prompt. These may overlap - they are merged / deduplicated in
@@ -106,6 +89,16 @@ pub struct PlannedPrompt<'a> {
budget_used: usize,
}
pub fn system_prompt(format: PromptFormat) -> &'static str {
match format {
PromptFormat::MarkedExcerpt => MARKED_EXCERPT_SYSTEM_PROMPT,
PromptFormat::LabeledSections => LABELED_SECTIONS_SYSTEM_PROMPT,
PromptFormat::NumberedLines => NUMBERED_LINES_SYSTEM_PROMPT,
// only intended for use via zeta_cli
PromptFormat::OnlySnippets => "",
}
}
#[derive(Clone, Debug)]
pub struct PlannedSnippet<'a> {
path: Arc<Path>,
@@ -404,63 +397,21 @@ impl<'a> PlannedPrompt<'a> {
),
],
PromptFormat::LabeledSections => vec![(self.request.cursor_point, CURSOR_MARKER)],
PromptFormat::NumLinesUniDiff => {
vec![(self.request.cursor_point, CURSOR_MARKER)]
}
PromptFormat::NumberedLines => vec![(self.request.cursor_point, CURSOR_MARKER)],
PromptFormat::OnlySnippets => vec![],
};
let mut prompt = match self.request.prompt_format {
PromptFormat::MarkedExcerpt => MARKED_EXCERPT_INSTRUCTIONS.to_string(),
PromptFormat::LabeledSections => LABELED_SECTIONS_INSTRUCTIONS.to_string(),
PromptFormat::NumLinesUniDiff => NUMBERED_LINES_INSTRUCTIONS.to_string(),
// only intended for use via zeta_cli
PromptFormat::OnlySnippets => String::new(),
};
let mut prompt = String::new();
prompt.push_str("## User Edits\n\n");
if self.request.events.is_empty() {
prompt.push_str("No edits yet.\n\n");
prompt.push_str("No edits yet.\n");
} else {
prompt.push_str(
"The following are the latest edits made by the user, from earlier to later.\n\n",
);
Self::push_events(&mut prompt, &self.request.events);
}
if self.request.prompt_format == PromptFormat::NumLinesUniDiff {
if self.request.referenced_declarations.is_empty() {
prompt.push_str(indoc! {"
# File under the cursor:
The cursor marker <|user_cursor|> indicates the current user cursor position.
The file is in current state, edits from edit history have been applied.
We prepend line numbers (e.g., `123|<actual line>`); they are not part of the file.
"});
} else {
// Note: This hasn't been trained on yet
prompt.push_str(indoc! {"
# Code Excerpts:
The cursor marker <|user_cursor|> indicates the current user cursor position.
Other excerpts of code from the project have been included as context based on their similarity to the code under the cursor.
Context excerpts are not guaranteed to be relevant, so use your own judgement.
Files are in their current state, edits from edit history have been applied.
We prepend line numbers (e.g., `123|<actual line>`); they are not part of the file.
"});
}
} else {
prompt.push_str("\n## Code\n\n");
}
prompt.push_str("\n## Code\n\n");
let section_labels =
self.push_file_snippets(&mut prompt, &mut excerpt_file_insertions, file_snippets)?;
if self.request.prompt_format == PromptFormat::NumLinesUniDiff {
prompt.push_str(UNIFIED_DIFF_REMINDER);
}
Ok((prompt, section_labels))
}
@@ -551,7 +502,7 @@ impl<'a> PlannedPrompt<'a> {
match self.request.prompt_format {
PromptFormat::MarkedExcerpt
| PromptFormat::OnlySnippets
| PromptFormat::NumLinesUniDiff => {
| PromptFormat::NumberedLines => {
if range.start.0 > 0 && !skipped_last_snippet {
output.push_str("\n");
}
@@ -569,7 +520,7 @@ impl<'a> PlannedPrompt<'a> {
}
let push_full_snippet = |output: &mut String| {
if self.request.prompt_format == PromptFormat::NumLinesUniDiff {
if self.request.prompt_format == PromptFormat::NumberedLines {
for (i, line) in snippet.text.lines().enumerate() {
writeln!(output, "{}|{}", i as u32 + range.start.0 + 1, line)?;
}
@@ -592,7 +543,7 @@ impl<'a> PlannedPrompt<'a> {
} else if !excerpt_file_insertions.is_empty() {
let lines = snippet.text.lines().collect::<Vec<_>>();
let push_line = |output: &mut String, line_ix: usize| {
if self.request.prompt_format == PromptFormat::NumLinesUniDiff {
if self.request.prompt_format == PromptFormat::NumberedLines {
write!(output, "{}|", line_ix as u32 + range.start.0 + 1)?;
}
anyhow::Ok(writeln!(output, "{}", lines[line_ix])?)
@@ -609,7 +560,7 @@ impl<'a> PlannedPrompt<'a> {
push_line(output, line_ix)?;
}
if let Some(next_line) = lines.get(insertion_line_ix) {
if self.request.prompt_format == PromptFormat::NumLinesUniDiff {
if self.request.prompt_format == PromptFormat::NumberedLines {
write!(
output,
"{}|",

View File

@@ -27,7 +27,6 @@ pub use predict_edits_v3::Line;
#[derive(Clone, Debug, PartialEq)]
pub struct EditPredictionContextOptions {
pub use_imports: bool,
pub use_references: bool,
pub excerpt: EditPredictionExcerptOptions,
pub score: EditPredictionScoreOptions,
}
@@ -117,23 +116,19 @@ impl EditPredictionContext {
index_state,
)?;
let excerpt_text = excerpt.text(buffer);
let excerpt_occurrences = text_similarity::Occurrences::within_string(&excerpt_text.body);
let declarations = if options.use_references
&& let Some(index_state) = index_state
{
let excerpt_occurrences =
text_similarity::Occurrences::within_string(&excerpt_text.body);
let adjacent_start = Point::new(cursor_point.row.saturating_sub(2), 0);
let adjacent_end = Point::new(cursor_point.row + 1, 0);
let adjacent_occurrences = text_similarity::Occurrences::within_string(
&buffer
.text_for_range(adjacent_start..adjacent_end)
.collect::<String>(),
);
let adjacent_start = Point::new(cursor_point.row.saturating_sub(2), 0);
let adjacent_end = Point::new(cursor_point.row + 1, 0);
let adjacent_occurrences = text_similarity::Occurrences::within_string(
&buffer
.text_for_range(adjacent_start..adjacent_end)
.collect::<String>(),
);
let cursor_offset_in_file = cursor_point.to_offset(buffer);
let cursor_offset_in_file = cursor_point.to_offset(buffer);
let declarations = if let Some(index_state) = index_state {
let references = get_references(&excerpt, &excerpt_text, buffer);
scored_declarations(
@@ -200,7 +195,6 @@ mod tests {
buffer_snapshot,
EditPredictionContextOptions {
use_imports: true,
use_references: true,
excerpt: EditPredictionExcerptOptions {
max_bytes: 60,
min_bytes: 10,

View File

@@ -3899,9 +3899,6 @@ impl Editor {
}
})
.collect::<Vec<_>>();
if selection_ranges.is_empty() {
return;
}
let ranges = match columnar_state {
ColumnarSelectionState::FromMouse { .. } => {

View File

@@ -7212,16 +7212,9 @@ impl EditorElement {
* ScrollPixelOffset::from(max_glyph_advance)
- ScrollPixelOffset::from(delta.x * scroll_sensitivity))
/ ScrollPixelOffset::from(max_glyph_advance);
let scale_factor = window.scale_factor();
let y = (current_scroll_position.y
* ScrollPixelOffset::from(line_height)
* ScrollPixelOffset::from(scale_factor)
let y = (current_scroll_position.y * ScrollPixelOffset::from(line_height)
- ScrollPixelOffset::from(delta.y * scroll_sensitivity))
.round()
/ ScrollPixelOffset::from(line_height)
/ ScrollPixelOffset::from(scale_factor);
/ ScrollPixelOffset::from(line_height);
let mut scroll_position =
point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
let forbid_vertical_scroll = editor.scroll_manager.forbid_vertical_scroll();

View File

@@ -493,15 +493,22 @@ pub fn show_link_definition(
}
let trigger_anchor = trigger_point.anchor();
let anchor = snapshot.buffer_snapshot().anchor_before(*trigger_anchor);
let Some(buffer) = editor.buffer().read(cx).buffer_for_anchor(anchor, cx) else {
let Some((buffer, buffer_position)) = editor
.buffer
.read(cx)
.text_anchor_for_position(*trigger_anchor, cx)
else {
return;
};
let Anchor {
excerpt_id,
text_anchor,
..
} = anchor;
let Some((excerpt_id, _, _)) = editor
.buffer()
.read(cx)
.excerpt_containing(*trigger_anchor, cx)
else {
return;
};
let same_kind = hovered_link_state.preferred_kind == preferred_kind
|| hovered_link_state
.links
@@ -531,7 +538,7 @@ pub fn show_link_definition(
async move {
let result = match &trigger_point {
TriggerPoint::Text(_) => {
if let Some((url_range, url)) = find_url(&buffer, text_anchor, cx.clone()) {
if let Some((url_range, url)) = find_url(&buffer, buffer_position, cx.clone()) {
this.read_with(cx, |_, _| {
let range = maybe!({
let start =
@@ -543,7 +550,7 @@ pub fn show_link_definition(
})
.ok()
} else if let Some((filename_range, filename)) =
find_file(&buffer, project.clone(), text_anchor, cx).await
find_file(&buffer, project.clone(), buffer_position, cx).await
{
let range = maybe!({
let start =
@@ -555,7 +562,7 @@ pub fn show_link_definition(
Some((range, vec![HoverLink::File(filename)]))
} else if let Some(provider) = provider {
let task = cx.update(|_, cx| {
provider.definitions(&buffer, text_anchor, preferred_kind, cx)
provider.definitions(&buffer, buffer_position, preferred_kind, cx)
})?;
if let Some(task) = task {
task.await.ok().flatten().map(|definition_result| {

View File

@@ -2679,15 +2679,6 @@ impl Pixels {
Self(self.0.floor())
}
/// Rounds the `Pixels` value to the nearest pixel accounting for scaling.
///
/// # Returns
///
/// Returns a new `Pixels` instance with the rounded value.
pub fn round_pixel(&self, scale_factor: f32) -> Self {
Self((self.0 * scale_factor).round() / scale_factor)
}
/// Rounds the `Pixels` value to the nearest whole number.
///
/// # Returns

View File

@@ -196,9 +196,8 @@ fn paint_line(
window: &mut Window,
cx: &mut App,
) -> Result<()> {
let scale_factor = window.scale_factor();
let line_bounds = Bounds::new(
point(origin.x, origin.y.round_pixel(scale_factor)),
origin,
size(
layout.width,
line_height * (wrap_boundaries.len() as f32 + 1.),
@@ -206,6 +205,7 @@ fn paint_line(
);
window.paint_layer(line_bounds, |window| {
let padding_top = (line_height - layout.ascent - layout.descent) / 2.;
let baseline_offset = point(px(0.), padding_top + layout.ascent);
let mut decoration_runs = decoration_runs.iter();
let mut wraps = wrap_boundaries.iter().peekable();
let mut run_end = 0;
@@ -213,11 +213,6 @@ fn paint_line(
let mut current_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
let mut current_strikethrough: Option<(Point<Pixels>, StrikethroughStyle)> = None;
let text_system = cx.text_system().clone();
let scale_factor = window.scale_factor();
let baseline_offset = point(
px(0.),
(padding_top + layout.ascent).round_pixel(scale_factor),
);
let mut glyph_origin = point(
aligned_origin_x(
origin,
@@ -227,7 +222,7 @@ fn paint_line(
layout,
wraps.peek(),
),
origin.y.round_pixel(scale_factor),
origin.y,
);
let mut prev_glyph_position = Point::default();
let mut max_glyph_size = size(px(0.), px(0.));
@@ -278,7 +273,7 @@ fn paint_line(
layout,
wraps.peek(),
);
glyph_origin.y = (glyph_origin.y + line_height).round_pixel(scale_factor);
glyph_origin.y += line_height;
}
prev_glyph_position = glyph.position;

View File

@@ -2982,7 +2982,7 @@ impl Window {
})?
.expect("Callback above only errors or returns Some");
let bounds = Bounds {
origin: glyph_origin + raster_bounds.origin.map(Into::into),
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
size: tile.bounds.size.map(Into::into),
};
let content_mask = self.content_mask().scale(scale_factor);

View File

@@ -403,9 +403,6 @@ impl<'a> MarkdownParser<'a> {
if let Some(mut image) = image.take() {
if !text.is_empty() {
image.set_alt_text(std::mem::take(&mut text).into());
mem::take(&mut highlights);
mem::take(&mut region_ranges);
mem::take(&mut regions);
}
markdown_text_like.push(MarkdownParagraphChunk::Image(image));
}
@@ -1274,40 +1271,17 @@ mod tests {
panic!("Expected a paragraph");
};
assert_eq!(
paragraph[0],
MarkdownParagraphChunk::Image(Image {
source_range: 0..111,
link: Link::Web {
url: "https://blog.logrocket.com/wp-content/uploads/2024/04/exploring-zed-open-source-code-editor-rust-2.png".to_string(),
},
alt_text: Some("test".into()),
height: None,
width: None,
},)
);
}
#[gpui::test]
async fn test_image_alt_text() {
let parsed = parse("[![Zed](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/zed-industries/zed/main/assets/badge/v0.json)](https://zed.dev)\n ").await;
let paragraph = if let ParsedMarkdownElement::Paragraph(text) = &parsed.children[0] {
text
} else {
panic!("Expected a paragraph");
};
assert_eq!(
paragraph[0],
MarkdownParagraphChunk::Image(Image {
source_range: 0..142,
link: Link::Web {
url: "https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/zed-industries/zed/main/assets/badge/v0.json".to_string(),
},
alt_text: Some("Zed".into()),
height: None,
width: None,
},)
);
paragraph[0],
MarkdownParagraphChunk::Image(Image {
source_range: 0..111,
link: Link::Web {
url: "https://blog.logrocket.com/wp-content/uploads/2024/04/exploring-zed-open-source-code-editor-rust-2.png".to_string(),
},
alt_text: Some("test".into()),
height: None,
width: None,
},)
);
}
#[gpui::test]

View File

@@ -1,18 +1,62 @@
use anyhow::Result;
use serde_json::Value;
use crate::patterns::migrate_language_setting;
pub fn remove_code_actions_on_format(value: &mut Value) -> Result<()> {
migrate_language_setting(value, remove_code_actions_on_format_inner)
let defaults =
settings::parse_json_with_comments::<Value>(settings::default_settings().as_ref()).unwrap();
let default_root_formatter = defaults.get("formatter");
let root_code_actions =
remove_code_actions_on_format_inner(value, default_root_formatter, &[], &[])?;
let user_default_formatter = value.get("formatter").cloned();
let user_languages = value
.as_object_mut()
.and_then(|obj| obj.get_mut("languages"))
.and_then(|languages| languages.as_object_mut());
let default_languages = defaults
.as_object()
.and_then(|obj| obj.get("languages"))
.and_then(|languages| languages.as_object());
if let Some(languages) = user_languages {
for (language_name, language) in languages.iter_mut() {
let path = vec!["languages", language_name];
let language_default_formatter = default_languages
.and_then(|langs| langs.get(language_name))
.and_then(|lang| lang.get("formatter"));
// override order:
// 4. root from defaults
// 3. language from defaults
// 2. root from user
// 1. language from user
let default_formatter_for_language = user_default_formatter
.as_ref()
.or(language_default_formatter)
.or(default_root_formatter);
remove_code_actions_on_format_inner(
language,
default_formatter_for_language,
&root_code_actions,
&path,
)?;
}
}
Ok(())
}
fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Result<()> {
fn remove_code_actions_on_format_inner(
value: &mut Value,
default_formatters: Option<&Value>,
parent_code_actions: &[String],
path: &[&str],
) -> Result<Vec<String>> {
let Some(obj) = value.as_object_mut() else {
return Ok(());
return Ok(vec![]);
};
let Some(code_actions_on_format) = obj.get("code_actions_on_format").cloned() else {
return Ok(());
return Ok(vec![]);
};
fn fmt_path(path: &[&str], key: &str) -> String {
@@ -35,6 +79,7 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
}
code_actions.push(code_action.clone());
}
code_actions.extend(parent_code_actions.iter().cloned());
let mut formatter_array = vec![];
if let Some(formatter) = obj.get("formatter") {
@@ -43,12 +88,18 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
} else {
formatter_array.insert(0, formatter.clone());
}
} else if let Some(formatter) = default_formatters {
if let Some(array) = formatter.as_array() {
formatter_array = array.clone();
} else {
formatter_array.push(formatter.clone());
}
};
let found_code_actions = !code_actions.is_empty();
formatter_array.splice(
0..0,
code_actions
.into_iter()
.iter()
.map(|code_action| serde_json::json!({"code_action": code_action})),
);
@@ -57,5 +108,5 @@ fn remove_code_actions_on_format_inner(value: &mut Value, path: &[&str]) -> Resu
obj.insert("formatter".to_string(), Value::Array(formatter_array));
}
Ok(())
Ok(code_actions)
}

View File

@@ -2010,7 +2010,8 @@ mod tests {
},
{
"code_action": "source.fixAll"
}
},
"auto"
]
}
"#
@@ -2041,7 +2042,8 @@ mod tests {
},
{
"code_action": "c"
}
},
"auto"
]
}
"#
@@ -2127,7 +2129,7 @@ mod tests {
"Go": {
"code_actions_on_format": {
"source.organizeImports": true
}
},
}
}
}"#
@@ -2139,14 +2141,19 @@ mod tests {
"formatter": [
{
"code_action": "source.fixAll.eslint"
}
},
"auto"
]
},
"Go": {
"formatter": [
{
"code_action": "source.organizeImports"
}
},
{
"code_action": "source.organizeImports"
},
"language_server"
]
}
}
@@ -2233,6 +2240,9 @@ mod tests {
{
"code_action": "source.organizeImports"
},
{
"code_action": "source.fixAll"
},
"rust-analyzer"
]
},
@@ -2240,7 +2250,14 @@ mod tests {
"formatter": [
{
"code_action": "source.organizeImports"
}
},
{
"code_action": "source.fixAll"
},
{
"code_action": "source.fixAll"
},
"prettier"
]
}
}
@@ -2250,6 +2267,35 @@ mod tests {
);
}
#[test]
fn test_code_actions_on_format_inserts_default_formatters() {
assert_migrate_settings_with_migrations(
&[MigrationType::Json(
migrations::m_2025_10_10::remove_code_actions_on_format,
)],
&r#"{
"code_actions_on_format": {
"source.organizeImports": false,
"source.fixAll.eslint": true
}
}"#
.unindent(),
Some(
&r#"
{
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
"#
.unindent(),
),
)
}
#[test]
fn test_code_actions_on_format_no_migration_when_not_present() {
assert_migrate_settings_with_migrations(

View File

@@ -1710,12 +1710,7 @@ impl LocalLspStore {
formatting_transaction_id,
cx,
|buffer, cx| {
zlog::info!(
"Applying edits {edits:?}. Content: {:?}",
buffer.text()
);
buffer.edit(edits, None, cx);
zlog::info!("Applied edits. New Content: {:?}", buffer.text());
},
)?;
}

View File

@@ -455,9 +455,8 @@ pub fn open_settings_editor(
if let Some(existing_window) = existing_window {
existing_window
.update(cx, |settings_window, window, cx| {
.update(cx, |settings_window, window, _| {
settings_window.original_window = Some(workspace_handle);
settings_window.observe_last_window_close(cx);
window.activate_window();
})
.ok();
@@ -1006,7 +1005,6 @@ impl SettingsWindow {
let mut this = Self {
title_bar,
original_window,
worktree_root_dirs: HashMap::default(),
files: vec![],
drop_down_file: None,
@@ -1044,8 +1042,6 @@ impl SettingsWindow {
list_state,
};
this.observe_last_window_close(cx);
this.fetch_files(window, cx);
this.build_ui(window, cx);
this.build_search_index();
@@ -1057,23 +1053,6 @@ impl SettingsWindow {
this
}
fn observe_last_window_close(&mut self, cx: &mut App) {
cx.on_window_closed(|cx| {
if let Some(existing_window) = cx
.windows()
.into_iter()
.find_map(|window| window.downcast::<SettingsWindow>())
&& cx.windows().len() == 1
{
cx.update_window(*existing_window, |_, window, _| {
window.remove_window();
})
.ok();
}
})
.detach();
}
fn toggle_navbar_entry(&mut self, nav_entry_index: usize) {
// We can only toggle root entries
if !self.navbar_entries[nav_entry_index].is_root {

View File

@@ -45,7 +45,6 @@ const MAX_EVENT_COUNT: usize = 16;
pub const DEFAULT_CONTEXT_OPTIONS: EditPredictionContextOptions = EditPredictionContextOptions {
use_imports: true,
use_references: false,
excerpt: EditPredictionExcerptOptions {
max_bytes: 512,
min_bytes: 128,

View File

@@ -20,11 +20,9 @@ use ui::{ContextMenu, ContextMenuEntry, DropdownMenu, prelude::*};
use ui_input::SingleLineInput;
use util::{ResultExt, paths::PathStyle, rel_path::RelPath};
use workspace::{Item, SplitDirection, Workspace};
use zeta2::{PredictionDebugInfo, Zeta, ZetaOptions};
use zeta2::{DEFAULT_CONTEXT_OPTIONS, PredictionDebugInfo, Zeta, ZetaOptions};
use edit_prediction_context::{
DeclarationStyle, EditPredictionContextOptions, EditPredictionExcerptOptions,
};
use edit_prediction_context::{DeclarationStyle, EditPredictionExcerptOptions};
actions!(
dev,
@@ -234,20 +232,17 @@ impl Zeta2Inspector {
.unwrap_or_default()
}
let zeta_options = this.zeta.read(cx).options().clone();
let context_options = EditPredictionContextOptions {
excerpt: EditPredictionExcerptOptions {
max_bytes: number_input_value(&this.max_excerpt_bytes_input, cx),
min_bytes: number_input_value(&this.min_excerpt_bytes_input, cx),
target_before_cursor_over_total_bytes: number_input_value(
&this.cursor_context_ratio_input,
cx,
),
},
..zeta_options.context
let mut context_options = DEFAULT_CONTEXT_OPTIONS.clone();
context_options.excerpt = EditPredictionExcerptOptions {
max_bytes: number_input_value(&this.max_excerpt_bytes_input, cx),
min_bytes: number_input_value(&this.min_excerpt_bytes_input, cx),
target_before_cursor_over_total_bytes: number_input_value(
&this.cursor_context_ratio_input,
cx,
),
};
let zeta_options = this.zeta.read(cx).options();
this.set_options(
ZetaOptions {
context: context_options,

View File

@@ -94,8 +94,6 @@ struct Zeta2Args {
file_indexing_parallelism: usize,
#[arg(long, default_value_t = false)]
disable_imports_gathering: bool,
#[arg(long, default_value_t = false)]
disable_reference_retrieval: bool,
}
#[derive(clap::ValueEnum, Default, Debug, Clone)]
@@ -113,7 +111,7 @@ impl Into<predict_edits_v3::PromptFormat> for PromptFormat {
Self::MarkedExcerpt => predict_edits_v3::PromptFormat::MarkedExcerpt,
Self::LabeledSections => predict_edits_v3::PromptFormat::LabeledSections,
Self::OnlySnippets => predict_edits_v3::PromptFormat::OnlySnippets,
Self::NumberedLines => predict_edits_v3::PromptFormat::NumLinesUniDiff,
Self::NumberedLines => predict_edits_v3::PromptFormat::NumberedLines,
}
}
}
@@ -302,7 +300,6 @@ impl Zeta2Args {
fn to_options(&self, omit_excerpt_overlaps: bool) -> zeta2::ZetaOptions {
zeta2::ZetaOptions {
context: EditPredictionContextOptions {
use_references: !self.disable_reference_retrieval,
use_imports: !self.disable_imports_gathering,
excerpt: EditPredictionExcerptOptions {
max_bytes: self.max_excerpt_bytes,

View File

@@ -320,13 +320,18 @@ To run linter fixes automatically on save:
```json [settings]
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
}
```
This specifies that when a format is requested, Zed will first run the `source.fixAll.eslint` action, and then perform the actual format using the language-specific default formatter (for JavaScript this is Prettier, and for other languages it often corresponds to formatting using the default language server).
### Integrating Formatting and Linting
Zed allows you to run both formatting and linting on save. Here's an example that uses Prettier for formatting and ESLint for linting JavaScript files:

View File

@@ -49,9 +49,12 @@ You can configure Zed to format code using `eslint --fix` by running the ESLint
{
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
}
}
@@ -63,9 +66,12 @@ You can also only execute a single ESLint rule when using `fixAll`:
{
"languages": {
"JavaScript": {
"formatter": {
"code_action": "source.fixAll.eslint"
}
"formatter": [
{
"code_action": "source.fixAll.eslint"
},
"auto"
]
}
},
"lsp": {