assistant: Normalize line endings for prompts loaded from the prompt library (#15708)

This PR makes it so we normalize the line endings for prompts to LFs
(`\n`) when we load a prompt from the library.

In some cases, prompts could end up with CRLF (`\r\n`) line endings.
When these prompts were used with the `/prompt` slash command and
summarily run, the prompt text would be converted into a rope, causing
the line endings to be normalized to LFs.

However, this would happen _after_ the ranges for the
`SlashCommandOutputSection`s were computed based on the text that still
contained the CRLFs. This would then cause these ranges to be invalid
for the text with the normalized endings, resulting in a panic when
converting them to anchors.

Fixes https://github.com/zed-industries/zed/issues/15652.

Release Notes:

- N/A

Co-authored-by: Max <max@zed.dev>
This commit is contained in:
Marshall Bowers 2024-08-02 18:13:17 -04:00 committed by GitHub
parent 3755f0d901
commit 91bbf0efc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 7 additions and 3 deletions

View file

@ -71,6 +71,7 @@ strsim.workspace = true
telemetry_events.workspace = true telemetry_events.workspace = true
terminal.workspace = true terminal.workspace = true
terminal_view.workspace = true terminal_view.workspace = true
text.workspace = true
theme.workspace = true theme.workspace = true
toml.workspace = true toml.workspace = true
ui.workspace = true ui.workspace = true

View file

@ -36,6 +36,7 @@ use std::{
sync::{atomic::AtomicBool, Arc}, sync::{atomic::AtomicBool, Arc},
time::Duration, time::Duration,
}; };
use text::LineEnding;
use theme::ThemeSettings; use theme::ThemeSettings;
use ui::{ use ui::{
div, prelude::*, IconButtonShape, ListItem, ListItemSpacing, ParentElement, Render, div, prelude::*, IconButtonShape, ListItem, ListItemSpacing, ParentElement, Render,
@ -1302,10 +1303,12 @@ impl PromptStore {
let bodies = self.bodies; let bodies = self.bodies;
self.executor.spawn(async move { self.executor.spawn(async move {
let txn = env.read_txn()?; let txn = env.read_txn()?;
Ok(bodies let mut prompt = bodies
.get(&txn, &id)? .get(&txn, &id)?
.ok_or_else(|| anyhow!("prompt not found"))? .ok_or_else(|| anyhow!("prompt not found"))?
.into()) .into();
LineEnding::normalize(&mut prompt);
Ok(prompt)
}) })
} }

View file

@ -60,7 +60,7 @@ pub type RenderFoldPlaceholder = Arc<
+ Fn(ElementId, Arc<dyn Fn(&mut WindowContext)>, &mut WindowContext) -> AnyElement, + Fn(ElementId, Arc<dyn Fn(&mut WindowContext)>, &mut WindowContext) -> AnyElement,
>; >;
#[derive(Default)] #[derive(Debug, Default)]
pub struct SlashCommandOutput { pub struct SlashCommandOutput {
pub text: String, pub text: String,
pub sections: Vec<SlashCommandOutputSection<usize>>, pub sections: Vec<SlashCommandOutputSection<usize>>,