Show annotations more like the inline assistant (#11530)

* compute gutter width
* show the AI icon
* borders, background, and text color for annotations

<img width="1840" alt="image"
src="https://github.com/zed-industries/zed/assets/836375/93f2e9b8-d7f7-4c25-b3e2-cf77a0c4ca36">

Release Notes:

- N/A
This commit is contained in:
Kyle Kelley 2024-05-07 19:16:35 -07:00 committed by GitHub
parent 1cf40d77e2
commit 6ddcff25e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 29 deletions

View file

@ -1,3 +1,3 @@
Use tools frequently, especially when referring to files and code. I prefer to see the file directly rather than you just chatting with me.
Use tools frequently, especially when referring to files and code. The Zed editor we're working in can show me files directly when you add annotations. Be concise in chat, bountiful in tool calling.
Teach me everything you can about settings files and how they're loaded.
Teach me everything you can about how zed loads settings. Please annotate the code inline.

View file

@ -36,7 +36,7 @@ use semantic_index::{CloudEmbeddingProvider, ProjectIndex, ProjectIndexDebugView
use serde::{Deserialize, Serialize};
use settings::Settings;
use std::sync::Arc;
use tools::OpenBufferTool;
use tools::AnnotationTool;
use ui::{ActiveFileButton, Composer, ProjectIndexButton};
use util::paths::CONVERSATIONS_DIR;
use util::{maybe, paths::EMBEDDINGS_DIR, ResultExt};
@ -150,7 +150,7 @@ impl AssistantPanel {
)
.unwrap();
tool_registry
.register(OpenBufferTool::new(workspace.clone(), project.clone()), cx)
.register(AnnotationTool::new(workspace.clone(), project.clone()), cx)
.unwrap();
let mut attachment_registry = AttachmentRegistry::new();

View file

@ -1,7 +1,7 @@
mod annotate_code;
mod create_buffer;
mod open_buffer;
mod project_index;
pub use annotate_code::*;
pub use create_buffer::*;
pub use open_buffer::*;
pub use project_index::*;

View file

@ -14,51 +14,51 @@ use ui::prelude::*;
use util::ResultExt;
use workspace::Workspace;
pub struct OpenBufferTool {
pub struct AnnotationTool {
workspace: WeakView<Workspace>,
project: Model<Project>,
}
impl OpenBufferTool {
impl AnnotationTool {
pub fn new(workspace: WeakView<Workspace>, project: Model<Project>) -> Self {
Self { workspace, project }
}
}
#[derive(Debug, Deserialize, JsonSchema, Clone)]
pub struct ExplainInput {
/// Name for this set of excerpts
pub struct AnnotationInput {
/// Name for this set of annotations
title: String,
excerpts: Vec<ExplainedExcerpt>,
annotations: Vec<Annotation>,
}
#[derive(Debug, Deserialize, JsonSchema, Clone)]
struct ExplainedExcerpt {
struct Annotation {
/// Path to the file
path: String,
/// Name of a symbol in the buffer to show
/// Name of a symbol in the code
symbol_name: String,
/// Text to display near the symbol definition
comment: String,
text: String,
}
impl LanguageModelTool for OpenBufferTool {
type Input = ExplainInput;
impl LanguageModelTool for AnnotationTool {
type Input = AnnotationInput;
type Output = String;
type View = OpenBufferView;
type View = AnnotationResultView;
fn name(&self) -> String {
"explain_code".to_string()
"annotate_code".to_string()
}
fn description(&self) -> String {
"Show and explain one or more code snippets from files in the current project. Code snippets are identified using a file path and the name of a symbol defined in that file.".to_string()
"Dynamically annotate symbols in the current codebase. Opens a buffer in a panel in their editor, to the side of the conversation. The annotations are shown in the editor as a block decoration.".to_string()
}
fn execute(&self, input: &Self::Input, cx: &mut WindowContext) -> Task<Result<Self::Output>> {
let workspace = self.workspace.clone();
let project = self.project.clone();
let excerpts = input.excerpts.clone();
let excerpts = input.annotations.clone();
let title = input.title.clone();
let worktree_id = project.update(cx, |project, cx| {
@ -115,11 +115,11 @@ impl LanguageModelTool for OpenBufferTool {
cx,
)
});
let explanation = SharedString::from(excerpt.comment.clone());
let explanation = SharedString::from(excerpt.text.clone());
editor.insert_blocks(
[BlockProperties {
position: ranges[0].start,
height: 1,
height: 2,
style: BlockStyle::Fixed,
render: Box::new(move |cx| {
Self::render_note_block(&explanation, cx)
@ -149,21 +149,41 @@ impl LanguageModelTool for OpenBufferTool {
output: Result<Self::Output>,
cx: &mut WindowContext,
) -> View<Self::View> {
cx.new_view(|_cx| OpenBufferView { output })
cx.new_view(|_cx| AnnotationResultView { output })
}
}
impl OpenBufferTool {
fn render_note_block(explanation: &SharedString, _cx: &mut BlockContext) -> AnyElement {
div().child(explanation.clone()).into_any_element()
impl AnnotationTool {
fn render_note_block(explanation: &SharedString, cx: &mut BlockContext) -> AnyElement {
let anchor_x = cx.anchor_x;
let gutter_width = cx.gutter_dimensions.width;
h_flex()
.w_full()
.py_2()
.border_y_1()
.border_color(cx.theme().colors().border)
.child(
h_flex()
.justify_center()
.w(gutter_width)
.child(Icon::new(IconName::Ai).color(Color::Hint)),
)
.child(
h_flex()
.w_full()
.ml(anchor_x - gutter_width)
.child(explanation.clone()),
)
.into_any_element()
}
}
pub struct OpenBufferView {
pub struct AnnotationResultView {
output: Result<String>,
}
impl Render for OpenBufferView {
impl Render for AnnotationResultView {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
match &self.output {
Ok(output) => div().child(output.clone().into_any_element()),
@ -172,7 +192,7 @@ impl Render for OpenBufferView {
}
}
impl ToolOutput for OpenBufferView {
impl ToolOutput for AnnotationResultView {
fn generate(&self, _: &mut ProjectContext, _: &mut WindowContext) -> String {
match &self.output {
Ok(output) => output.clone(),