Compare commits
17 Commits
fix-git-ht
...
v0.142.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2ab5eab81 | ||
|
|
beadb11a2f | ||
|
|
f7eca9ec9e | ||
|
|
5a2c5d2512 | ||
|
|
7cdf702819 | ||
|
|
34d7f1e345 | ||
|
|
53730e2aaa | ||
|
|
b48cc75fa9 | ||
|
|
071650ff61 | ||
|
|
86183ca65d | ||
|
|
075860d5cd | ||
|
|
67ba048581 | ||
|
|
d5fb290499 | ||
|
|
b01945e1de | ||
|
|
1b0b7fe064 | ||
|
|
985644bacb | ||
|
|
c686c4c800 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -254,7 +254,7 @@ jobs:
|
||||
target/aarch64-apple-darwin/release/Zed-aarch64.dmg
|
||||
target/x86_64-apple-darwin/release/Zed-x86_64.dmg
|
||||
target/release/Zed.dmg
|
||||
body_file: target/release-notes.md
|
||||
body_path: target/release-notes.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -13550,7 +13550,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.142.0"
|
||||
version = "0.142.5"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"anyhow",
|
||||
|
||||
@@ -131,14 +131,7 @@
|
||||
// The default number of lines to expand excerpts in the multibuffer by.
|
||||
"expand_excerpt_lines": 3,
|
||||
// Globs to match against file paths to determine if a file is private.
|
||||
"private_files": [
|
||||
"**/.env*",
|
||||
"**/*.pem",
|
||||
"**/*.key",
|
||||
"**/*.cert",
|
||||
"**/*.crt",
|
||||
"**/secrets.yml"
|
||||
],
|
||||
"private_files": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"],
|
||||
// Whether to use additional LSP queries to format (and amend) the code after
|
||||
// every "trigger" symbol input, defined by LSP server capabilities.
|
||||
"use_on_type_format": true,
|
||||
@@ -758,6 +751,11 @@
|
||||
"allowed": true
|
||||
}
|
||||
},
|
||||
"JSONC": {
|
||||
"prettier": {
|
||||
"allowed": true
|
||||
}
|
||||
},
|
||||
"Markdown": {
|
||||
"format_on_save": "off",
|
||||
"prettier": {
|
||||
|
||||
@@ -236,7 +236,7 @@ pub fn preprocess_anthropic_request(request: &mut LanguageModelRequest) {
|
||||
}
|
||||
|
||||
if !system_message.is_empty() {
|
||||
request.messages.insert(
|
||||
new_messages.insert(
|
||||
0,
|
||||
LanguageModelRequestMessage {
|
||||
role: Role::System,
|
||||
|
||||
@@ -6,118 +6,106 @@ pub fn generate_content_prompt(
|
||||
language_name: Option<&str>,
|
||||
buffer: BufferSnapshot,
|
||||
range: Range<usize>,
|
||||
project_name: Option<String>,
|
||||
_project_name: Option<String>,
|
||||
) -> anyhow::Result<String> {
|
||||
let mut prompt = String::new();
|
||||
|
||||
let content_type = match language_name {
|
||||
None | Some("Markdown" | "Plain Text") => {
|
||||
writeln!(prompt, "You are an expert engineer.")?;
|
||||
"Text"
|
||||
}
|
||||
Some(language_name) => {
|
||||
writeln!(prompt, "You are an expert {language_name} engineer.")?;
|
||||
writeln!(
|
||||
prompt,
|
||||
"Your answer MUST always and only be valid {}.",
|
||||
language_name
|
||||
"Here's a file of text that I'm going to ask you to make an edit to."
|
||||
)?;
|
||||
"Code"
|
||||
"text"
|
||||
}
|
||||
Some(language_name) => {
|
||||
writeln!(
|
||||
prompt,
|
||||
"Here's a file of {language_name} that I'm going to ask you to make an edit to."
|
||||
)?;
|
||||
"code"
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(project_name) = project_name {
|
||||
writeln!(
|
||||
prompt,
|
||||
"You are currently working inside the '{project_name}' project in code editor Zed."
|
||||
)?;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
prompt,
|
||||
"The user has the following file open in the editor:"
|
||||
)?;
|
||||
const MAX_CTX: usize = 50000;
|
||||
let mut is_truncated = false;
|
||||
if range.is_empty() {
|
||||
write!(prompt, "```")?;
|
||||
if let Some(language_name) = language_name {
|
||||
write!(prompt, "{language_name}")?;
|
||||
}
|
||||
|
||||
for chunk in buffer.as_rope().chunks_in_range(0..range.start) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
prompt.push_str("<|CURSOR|>");
|
||||
for chunk in buffer.as_rope().chunks_in_range(range.start..buffer.len()) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
if !prompt.ends_with('\n') {
|
||||
prompt.push('\n');
|
||||
}
|
||||
writeln!(prompt, "```")?;
|
||||
prompt.push('\n');
|
||||
|
||||
writeln!(
|
||||
prompt,
|
||||
"Assume the cursor is located where the `<|CURSOR|>` span is."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
prompt,
|
||||
"{content_type} can't be replaced, so assume your answer will be inserted at the cursor.",
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
prompt,
|
||||
"Generate {content_type} based on the users prompt: {user_prompt}",
|
||||
)
|
||||
.unwrap();
|
||||
prompt.push_str("The point you'll need to insert at is marked with <insert_here></insert_here>.\n\n<document>");
|
||||
} else {
|
||||
write!(prompt, "```")?;
|
||||
for chunk in buffer.as_rope().chunks() {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
if !prompt.ends_with('\n') {
|
||||
prompt.push('\n');
|
||||
}
|
||||
writeln!(prompt, "```")?;
|
||||
prompt.push('\n');
|
||||
|
||||
writeln!(
|
||||
prompt,
|
||||
"In particular, the following piece of text is selected:"
|
||||
)?;
|
||||
write!(prompt, "```")?;
|
||||
if let Some(language_name) = language_name {
|
||||
write!(prompt, "{language_name}")?;
|
||||
}
|
||||
prompt.push('\n');
|
||||
prompt.push_str("The section you'll need to rewrite is marked with <rewrite_this></rewrite_this> tags.\n\n<document>");
|
||||
}
|
||||
// Include file content.
|
||||
let before_range = 0..range.start;
|
||||
let truncated_before = if before_range.len() > MAX_CTX {
|
||||
is_truncated = true;
|
||||
range.start - MAX_CTX..range.start
|
||||
} else {
|
||||
before_range
|
||||
};
|
||||
let mut non_rewrite_len = truncated_before.len();
|
||||
for chunk in buffer.text_for_range(truncated_before) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
if !range.is_empty() {
|
||||
prompt.push_str("<rewrite_this>\n");
|
||||
for chunk in buffer.text_for_range(range.clone()) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
if !prompt.ends_with('\n') {
|
||||
prompt.push('\n');
|
||||
}
|
||||
writeln!(prompt, "```")?;
|
||||
prompt.push('\n');
|
||||
|
||||
writeln!(
|
||||
prompt,
|
||||
"Modify the user's selected {content_type} based upon the users prompt: {user_prompt}"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
prompt,
|
||||
"You must reply with only the adjusted {content_type}, not the entire file."
|
||||
)
|
||||
.unwrap();
|
||||
prompt.push_str("\n<rewrite_this>");
|
||||
} else {
|
||||
prompt.push_str("<insert_here></insert_here>");
|
||||
}
|
||||
let after_range = range.end..buffer.len();
|
||||
let truncated_after = if after_range.len() > MAX_CTX {
|
||||
is_truncated = true;
|
||||
range.end..range.end + MAX_CTX
|
||||
} else {
|
||||
after_range
|
||||
};
|
||||
non_rewrite_len += truncated_after.len();
|
||||
for chunk in buffer.text_for_range(truncated_after) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
|
||||
writeln!(prompt, "Never make remarks about the output.").unwrap();
|
||||
writeln!(
|
||||
prompt,
|
||||
"Do not return anything else, except the generated {content_type}."
|
||||
)
|
||||
.unwrap();
|
||||
write!(prompt, "</document>\n\n").unwrap();
|
||||
|
||||
if is_truncated {
|
||||
writeln!(prompt, "The context around the relevant section has been truncated (possibly in the middle of a line) for brevity.\n")?;
|
||||
}
|
||||
|
||||
if range.is_empty() {
|
||||
writeln!(
|
||||
prompt,
|
||||
"You can't replace {content_type}, your answer will be inserted in place of the `<insert_here></insert_here>` tags. Don't include the insert_here tags in your output.",
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
prompt,
|
||||
"Generate {content_type} based on the following prompt:\n\n<prompt>\n{user_prompt}\n</prompt>",
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(prompt, "Match the indentation in the original file in the inserted {content_type}, don't include any indentation on blank lines.\n").unwrap();
|
||||
prompt.push_str("Immediately start with the following format with no remarks:\n\n```\n{{INSERTED_CODE}}\n```");
|
||||
} else {
|
||||
writeln!(prompt, "Edit the section of {content_type} in <rewrite_this></rewrite_this> tags based on the following prompt:'").unwrap();
|
||||
writeln!(prompt, "\n<prompt>\n{user_prompt}\n</prompt>\n").unwrap();
|
||||
let rewrite_len = range.end - range.start;
|
||||
if rewrite_len < 20000 && rewrite_len * 2 < non_rewrite_len {
|
||||
writeln!(prompt, "And here's the section to rewrite based on that prompt again for reference:\n\n<rewrite_this>\n").unwrap();
|
||||
for chunk in buffer.text_for_range(range.clone()) {
|
||||
prompt.push_str(chunk);
|
||||
}
|
||||
writeln!(prompt, "\n</rewrite_this>\n").unwrap();
|
||||
}
|
||||
writeln!(prompt, "Only make changes that are necessary to fulfill the prompt, leave everything else as-is. All surrounding {content_type} will be preserved.\n").unwrap();
|
||||
write!(
|
||||
prompt,
|
||||
"Start at the indentation level in the original file in the rewritten {content_type}. "
|
||||
)
|
||||
.unwrap();
|
||||
prompt.push_str("Don't stop until you've rewritten the entire section, even if you have no more changes to make, always write out the whole section with no unnecessary elisions.");
|
||||
prompt.push_str("\n\nImmediately start with the following format with no remarks:\n\n```\n{{REWRITTEN_CODE}}\n```");
|
||||
}
|
||||
|
||||
Ok(prompt)
|
||||
}
|
||||
|
||||
@@ -2914,6 +2914,9 @@ impl Editor {
|
||||
let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
|
||||
let end_offset = start_offset + end_difference;
|
||||
let start_offset = start_offset + start_difference;
|
||||
if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
|
||||
continue;
|
||||
}
|
||||
let start = buffer_snapshot.anchor_after(start_offset);
|
||||
let end = buffer_snapshot.anchor_after(end_offset);
|
||||
linked_edits
|
||||
@@ -6809,6 +6812,16 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
if self
|
||||
.context_menu
|
||||
.write()
|
||||
.as_mut()
|
||||
.map(|menu| menu.select_first(self.project.as_ref(), cx))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(self.mode, EditorMode::SingleLine { .. }) {
|
||||
cx.propagate();
|
||||
return;
|
||||
|
||||
@@ -549,11 +549,17 @@ pub struct Window {
|
||||
pub(crate) focus: Option<FocusId>,
|
||||
focus_enabled: bool,
|
||||
pending_input: Option<PendingInput>,
|
||||
pending_modifiers: Option<Modifiers>,
|
||||
pending_modifier: ModifierState,
|
||||
pending_input_observers: SubscriberSet<(), AnyObserver>,
|
||||
prompt: Option<RenderablePromptHandle>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct ModifierState {
|
||||
modifiers: Modifiers,
|
||||
saw_keystroke: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum DrawPhase {
|
||||
None,
|
||||
@@ -824,7 +830,7 @@ impl Window {
|
||||
focus: None,
|
||||
focus_enabled: true,
|
||||
pending_input: None,
|
||||
pending_modifiers: None,
|
||||
pending_modifier: ModifierState::default(),
|
||||
pending_input_observers: SubscriberSet::new(),
|
||||
prompt: None,
|
||||
})
|
||||
@@ -3168,9 +3174,12 @@ impl<'a> WindowContext<'a> {
|
||||
let mut keystroke: Option<Keystroke> = None;
|
||||
|
||||
if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
|
||||
if let Some(previous) = self.window.pending_modifiers.take() {
|
||||
if event.modifiers.number_of_modifiers() == 0
|
||||
&& self.window.pending_modifier.modifiers.number_of_modifiers() == 1
|
||||
&& !self.window.pending_modifier.saw_keystroke
|
||||
{
|
||||
if event.modifiers.number_of_modifiers() == 0 {
|
||||
let key = match previous {
|
||||
let key = match self.window.pending_modifier.modifiers {
|
||||
modifiers if modifiers.shift => Some("shift"),
|
||||
modifiers if modifiers.control => Some("control"),
|
||||
modifiers if modifiers.alt => Some("alt"),
|
||||
@@ -3198,17 +3207,15 @@ impl<'a> WindowContext<'a> {
|
||||
pending = pending_bindings;
|
||||
}
|
||||
}
|
||||
} else if event.modifiers.number_of_modifiers() == 1 {
|
||||
self.window.pending_modifiers = Some(event.modifiers);
|
||||
}
|
||||
if keystroke.is_none() {
|
||||
self.finish_dispatch_key_event(event, dispatch_path);
|
||||
return;
|
||||
if self.window.pending_modifier.modifiers.number_of_modifiers() == 0
|
||||
&& event.modifiers.number_of_modifiers() == 1
|
||||
{
|
||||
self.window.pending_modifier.saw_keystroke = false
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
|
||||
self.window.pending_modifiers.take();
|
||||
self.window.pending_modifier.modifiers = event.modifiers
|
||||
} else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
|
||||
self.window.pending_modifier.saw_keystroke = true;
|
||||
let KeymatchResult {
|
||||
bindings: key_down_bindings,
|
||||
pending: key_down_pending,
|
||||
@@ -3224,6 +3231,11 @@ impl<'a> WindowContext<'a> {
|
||||
pending = key_down_pending;
|
||||
}
|
||||
|
||||
if keystroke.is_none() {
|
||||
self.finish_dispatch_key_event(event, dispatch_path);
|
||||
return;
|
||||
}
|
||||
|
||||
if pending {
|
||||
let mut currently_pending = self.window.pending_input.take().unwrap_or_default();
|
||||
if currently_pending.focus.is_some() && currently_pending.focus != self.window.focus {
|
||||
|
||||
@@ -348,7 +348,7 @@ impl LspAdapter for NodeVersionAdapter {
|
||||
}
|
||||
|
||||
Ok(LanguageServerBinary {
|
||||
path: destination_path.join("package-version-server"),
|
||||
path: destination_path,
|
||||
env: None,
|
||||
arguments: Default::default(),
|
||||
})
|
||||
|
||||
@@ -272,6 +272,7 @@ pub enum Event {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SerializedOutlinePanel {
|
||||
width: Option<Pixels>,
|
||||
active: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn init_settings(cx: &mut AppContext) {
|
||||
@@ -312,6 +313,7 @@ impl OutlinePanel {
|
||||
if let Some(serialized_panel) = serialized_panel {
|
||||
panel.update(cx, |panel, cx| {
|
||||
panel.width = serialized_panel.width.map(|px| px.round());
|
||||
panel.active = serialized_panel.active.unwrap_or(false);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
@@ -407,12 +409,13 @@ impl OutlinePanel {
|
||||
|
||||
fn serialize(&mut self, cx: &mut ViewContext<Self>) {
|
||||
let width = self.width;
|
||||
let active = Some(self.active);
|
||||
self.pending_serialization = cx.background_executor().spawn(
|
||||
async move {
|
||||
KEY_VALUE_STORE
|
||||
.write_kvp(
|
||||
OUTLINE_PANEL_KEY.into(),
|
||||
serde_json::to_string(&SerializedOutlinePanel { width })?,
|
||||
serde_json::to_string(&SerializedOutlinePanel { width, active })?,
|
||||
)
|
||||
.await?;
|
||||
anyhow::Ok(())
|
||||
@@ -2522,7 +2525,7 @@ impl Panel for OutlinePanel {
|
||||
}
|
||||
|
||||
fn starts_open(&self, _: &WindowContext) -> bool {
|
||||
self.active_item.is_some()
|
||||
self.active
|
||||
}
|
||||
|
||||
fn set_active(&mut self, active: bool, cx: &mut ViewContext<Self>) {
|
||||
@@ -2551,6 +2554,7 @@ impl Panel for OutlinePanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.serialize(cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -317,11 +317,14 @@ impl Prettier {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let prettier_parser = prettier_settings.parser.as_deref().or_else(|| buffer_language.and_then(|language| language.prettier_parser_name()));
|
||||
let mut prettier_parser = prettier_settings.parser.as_deref();
|
||||
if buffer_path.is_none() {
|
||||
prettier_parser = prettier_parser.or_else(|| buffer_language.and_then(|language| language.prettier_parser_name()));
|
||||
if prettier_parser.is_none() {
|
||||
log::error!("Formatting unsaved file with prettier failed. No prettier parser configured for language {buffer_language:?}");
|
||||
return Err(anyhow!("Cannot determine prettier parser for unsaved file"));
|
||||
}
|
||||
|
||||
if prettier_parser.is_none() && buffer_path.is_none() {
|
||||
log::error!("Formatting unsaved file with prettier failed. No prettier parser configured for language {buffer_language:?}");
|
||||
return Err(anyhow!("Cannot determine prettier parser for unsaved file"));
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
|
||||
@@ -8192,7 +8192,7 @@ impl Project {
|
||||
}
|
||||
};
|
||||
|
||||
if abs_path.ends_with(local_settings_file_relative_path()) {
|
||||
if path.ends_with(local_settings_file_relative_path()) {
|
||||
let settings_dir = Arc::from(
|
||||
path.ancestors()
|
||||
.nth(local_settings_file_relative_path().components().count())
|
||||
@@ -8209,7 +8209,7 @@ impl Project {
|
||||
},
|
||||
)
|
||||
});
|
||||
} else if abs_path.ends_with(local_tasks_file_relative_path()) {
|
||||
} else if path.ends_with(local_tasks_file_relative_path()) {
|
||||
self.task_inventory().update(cx, |task_inventory, cx| {
|
||||
if removed {
|
||||
task_inventory.remove_local_static_source(&abs_path);
|
||||
@@ -8229,7 +8229,7 @@ impl Project {
|
||||
);
|
||||
}
|
||||
})
|
||||
} else if abs_path.ends_with(local_vscode_tasks_file_relative_path()) {
|
||||
} else if path.ends_with(local_vscode_tasks_file_relative_path()) {
|
||||
self.task_inventory().update(cx, |task_inventory, cx| {
|
||||
if removed {
|
||||
task_inventory.remove_local_static_source(&abs_path);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.142.0"
|
||||
version = "0.142.5"
|
||||
publish = false
|
||||
license = "GPL-3.0-or-later"
|
||||
authors = ["Zed Team <hi@zed.dev>"]
|
||||
|
||||
@@ -1 +1 @@
|
||||
dev
|
||||
stable
|
||||
Reference in New Issue
Block a user