mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-09 10:56:20 +00:00
WIP
This commit is contained in:
parent
eff925cb6a
commit
4863c9ac25
7 changed files with 441 additions and 377 deletions
|
@ -1696,6 +1696,11 @@ impl Editor {
|
|||
let focus_handle = cx.focus_handle();
|
||||
cx.on_focus(&focus_handle, Self::handle_focus).detach();
|
||||
cx.on_blur(&focus_handle, Self::handle_blur).detach();
|
||||
cx.on_release(|this, cx| {
|
||||
//todo!()
|
||||
//cx.emit_global(EditorReleased(self.handle.clone()));
|
||||
})
|
||||
.detach();
|
||||
|
||||
let mut this = Self {
|
||||
handle: cx.view().downgrade(),
|
||||
|
@ -9240,14 +9245,6 @@ pub struct EditorFocused(pub View<Editor>);
|
|||
pub struct EditorBlurred(pub View<Editor>);
|
||||
pub struct EditorReleased(pub WeakView<Editor>);
|
||||
|
||||
// impl Entity for Editor {
|
||||
// type Event = Event;
|
||||
|
||||
// fn release(&mut self, cx: &mut AppContext) {
|
||||
// cx.emit_global(EditorReleased(self.handle.clone()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
impl EventEmitter<EditorEvent> for Editor {}
|
||||
|
||||
impl FocusableView for Editor {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
use gpui::{AnyElement, Render, ViewContext, WeakView};
|
||||
use ui::{prelude::*, ButtonCommon, Icon, IconButton, Tooltip};
|
||||
use workspace::{StatusItemView, Workspace};
|
||||
use workspace::{item::ItemHandle, StatusItemView, Workspace};
|
||||
|
||||
use crate::feedback_modal::FeedbackModal;
|
||||
use crate::feedback_editor::FeedbackEditor;
|
||||
|
||||
pub struct DeployFeedbackButton {
|
||||
_active: bool,
|
||||
active: bool,
|
||||
workspace: WeakView<Workspace>,
|
||||
}
|
||||
|
||||
impl DeployFeedbackButton {
|
||||
pub fn new(workspace: &Workspace) -> Self {
|
||||
DeployFeedbackButton {
|
||||
_active: false,
|
||||
active: false,
|
||||
workspace: workspace.weak_handle(),
|
||||
}
|
||||
}
|
||||
|
@ -22,37 +22,34 @@ impl Render for DeployFeedbackButton {
|
|||
type Element = AnyElement;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let is_open = self
|
||||
.workspace
|
||||
.upgrade()
|
||||
.and_then(|workspace| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.active_modal::<FeedbackModal>(cx)
|
||||
})
|
||||
})
|
||||
.is_some();
|
||||
let active = self.active;
|
||||
|
||||
IconButton::new("give-feedback", Icon::Envelope)
|
||||
.style(ui::ButtonStyle::Subtle)
|
||||
.selected(is_open)
|
||||
.tooltip(|cx| Tooltip::text("Give Feedback", cx))
|
||||
.on_click(cx.listener(|this, _, cx| {
|
||||
.on_click(cx.listener(move |this, _, cx| {
|
||||
let Some(workspace) = this.workspace.upgrade() else {
|
||||
return;
|
||||
};
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.toggle_modal(cx, |cx| FeedbackModal::new(cx))
|
||||
})
|
||||
|
||||
if !active {
|
||||
workspace.update(cx, |workspace, cx| FeedbackEditor::deploy(workspace, cx))
|
||||
}
|
||||
}))
|
||||
.into_any_element()
|
||||
}
|
||||
}
|
||||
|
||||
impl StatusItemView for DeployFeedbackButton {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
_active_pane_item: Option<&dyn workspace::item::ItemHandle>,
|
||||
_cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
// no-op
|
||||
fn set_active_pane_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext<Self>) {
|
||||
if let Some(item) = item {
|
||||
if let Some(_) = item.downcast::<FeedbackEditor>() {
|
||||
self.active = true;
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.active = false;
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use workspace::Workspace;
|
|||
pub mod deploy_feedback_button;
|
||||
pub mod feedback_editor;
|
||||
pub mod feedback_info_text;
|
||||
pub mod feedback_modal;
|
||||
// pub mod feedback_modal;
|
||||
pub mod submit_feedback_button;
|
||||
|
||||
mod system_specs;
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
use std::{ops::RangeInclusive, sync::Arc};
|
||||
|
||||
use crate::system_specs::SystemSpecs;
|
||||
use anyhow::bail;
|
||||
use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
|
||||
use editor::Editor;
|
||||
use editor::{Anchor, Editor, EditorEvent};
|
||||
use futures::AsyncReadExt;
|
||||
use gpui::{
|
||||
actions, serde_json, AppContext, Model, PromptLevel, Task, View, ViewContext, VisualContext,
|
||||
actions, serde_json, AnyElement, AnyView, AppContext, Div, EntityId, EventEmitter,
|
||||
FocusableView, Model, PromptLevel, Task, View, ViewContext, WindowContext,
|
||||
};
|
||||
use isahc::Request;
|
||||
use language::Buffer;
|
||||
use project::Project;
|
||||
use language::{Buffer, Event};
|
||||
use project::{search::SearchQuery, Project};
|
||||
use regex::Regex;
|
||||
use serde_derive::Serialize;
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
ops::{Range, RangeInclusive},
|
||||
sync::Arc,
|
||||
};
|
||||
use ui::{prelude::*, Icon, IconElement, Label};
|
||||
use util::ResultExt;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::system_specs::SystemSpecs;
|
||||
use workspace::{
|
||||
item::{Item, ItemEvent, ItemHandle},
|
||||
searchable::{SearchEvent, SearchableItem, SearchableItemHandle},
|
||||
Workspace,
|
||||
};
|
||||
|
||||
const FEEDBACK_CHAR_LIMIT: RangeInclusive<usize> = 10..=5000;
|
||||
const FEEDBACK_SUBMISSION_ERROR_TEXT: &str =
|
||||
|
@ -24,12 +32,10 @@ const FEEDBACK_SUBMISSION_ERROR_TEXT: &str =
|
|||
actions!(GiveFeedback, SubmitFeedback);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.observe_new_views(|workspace: &mut Workspace, cx| {
|
||||
workspace.register_action(
|
||||
move |workspace: &mut Workspace, _: &GiveFeedback, cx: &mut ViewContext<Workspace>| {
|
||||
FeedbackEditor::deploy(workspace, cx);
|
||||
},
|
||||
);
|
||||
cx.observe_new_views(|workspace: &mut Workspace, _| {
|
||||
workspace.register_action(|workspace, _: &GiveFeedback, cx| {
|
||||
FeedbackEditor::deploy(workspace, cx);
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
@ -53,6 +59,9 @@ pub(crate) struct FeedbackEditor {
|
|||
pub allow_submission: bool,
|
||||
}
|
||||
|
||||
impl EventEmitter<Event> for FeedbackEditor {}
|
||||
impl EventEmitter<EditorEvent> for FeedbackEditor {}
|
||||
|
||||
impl FeedbackEditor {
|
||||
fn new(
|
||||
system_specs: SystemSpecs,
|
||||
|
@ -66,8 +75,11 @@ impl FeedbackEditor {
|
|||
editor
|
||||
});
|
||||
|
||||
cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()))
|
||||
.detach();
|
||||
cx.subscribe(
|
||||
&editor,
|
||||
|&mut _, _, e: &EditorEvent, cx: &mut ViewContext<_>| cx.emit(e.clone()),
|
||||
)
|
||||
.detach();
|
||||
|
||||
Self {
|
||||
system_specs: system_specs.clone(),
|
||||
|
@ -101,11 +113,15 @@ impl FeedbackEditor {
|
|||
};
|
||||
|
||||
if let Some(error) = error {
|
||||
cx.prompt(PromptLevel::Critical, &error, &["OK"]);
|
||||
let prompt = cx.prompt(PromptLevel::Critical, &error, &["OK"]);
|
||||
cx.spawn(|_, _cx| async move {
|
||||
prompt.await.ok();
|
||||
})
|
||||
.detach();
|
||||
return Task::ready(Ok(()));
|
||||
}
|
||||
|
||||
let mut answer = cx.prompt(
|
||||
let answer = cx.prompt(
|
||||
PromptLevel::Info,
|
||||
"Ready to submit your feedback?",
|
||||
&["Yes, Submit!", "No"],
|
||||
|
@ -115,7 +131,7 @@ impl FeedbackEditor {
|
|||
let specs = self.system_specs.clone();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let answer = answer.recv().await;
|
||||
let answer = answer.await.ok();
|
||||
|
||||
if answer == Some(0) {
|
||||
this.update(&mut cx, |feedback_editor, cx| {
|
||||
|
@ -125,18 +141,22 @@ impl FeedbackEditor {
|
|||
|
||||
match FeedbackEditor::submit_feedback(&feedback_text, client, specs).await {
|
||||
Ok(_) => {
|
||||
this.update(&mut cx, |_, cx| cx.emit(editor::EditorEvent::Closed))
|
||||
this.update(&mut cx, |_, cx| cx.emit(Event::Closed))
|
||||
.log_err();
|
||||
}
|
||||
|
||||
Err(error) => {
|
||||
log::error!("{}", error);
|
||||
this.update(&mut cx, |feedback_editor, cx| {
|
||||
cx.prompt(
|
||||
let prompt = cx.prompt(
|
||||
PromptLevel::Critical,
|
||||
FEEDBACK_SUBMISSION_ERROR_TEXT,
|
||||
&["OK"],
|
||||
);
|
||||
cx.spawn(|_, _cx| async move {
|
||||
prompt.await.ok();
|
||||
})
|
||||
.detach();
|
||||
feedback_editor.set_allow_submission(true, cx);
|
||||
})
|
||||
.log_err();
|
||||
|
@ -234,200 +254,232 @@ impl FeedbackEditor {
|
|||
}
|
||||
}
|
||||
|
||||
// impl View for FeedbackEditor {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "FeedbackEditor"
|
||||
// }
|
||||
// TODO
|
||||
impl Render for FeedbackEditor {
|
||||
type Element = Div;
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// ChildView::new(&self.editor, cx).into_any()
|
||||
// }
|
||||
fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
|
||||
div().size_full().child(self.editor.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
|
||||
// if cx.is_self_focused() {
|
||||
// cx.focus(&self.editor);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl EventEmitter<ItemEvent> for FeedbackEditor {}
|
||||
|
||||
// impl Entity for FeedbackEditor {
|
||||
// type Event = editor::Event;
|
||||
// }
|
||||
impl FocusableView for FeedbackEditor {
|
||||
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
|
||||
self.editor.focus_handle(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// impl Item for FeedbackEditor {
|
||||
// fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
|
||||
// Some("Send Feedback".into())
|
||||
// }
|
||||
impl Item for FeedbackEditor {
|
||||
fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
|
||||
Some("Send Feedback".into())
|
||||
}
|
||||
|
||||
// fn tab_content<T: 'static>(
|
||||
// &self,
|
||||
// _: Option<usize>,
|
||||
// style: &theme::Tab,
|
||||
// _: &AppContext,
|
||||
// ) -> AnyElement<T> {
|
||||
// Flex::row()
|
||||
// .with_child(
|
||||
// Svg::new("icons/feedback.svg")
|
||||
// .with_color(style.label.text.color)
|
||||
// .constrained()
|
||||
// .with_width(style.type_icon_width)
|
||||
// .aligned()
|
||||
// .contained()
|
||||
// .with_margin_right(style.spacing),
|
||||
// )
|
||||
// .with_child(
|
||||
// Label::new("Send Feedback", style.label.clone())
|
||||
// .aligned()
|
||||
// .contained(),
|
||||
// )
|
||||
// .into_any()
|
||||
// }
|
||||
fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
|
||||
h_stack()
|
||||
.gap_1()
|
||||
.child(IconElement::new(Icon::Envelope).color(Color::Accent))
|
||||
.child(Label::new("Send Feedback".to_string()))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
// fn for_each_project_item(&self, cx: &AppContext, f: &mut dyn FnMut(usize, &dyn project::Item)) {
|
||||
// self.editor.for_each_project_item(cx, f)
|
||||
// }
|
||||
fn for_each_project_item(
|
||||
&self,
|
||||
cx: &AppContext,
|
||||
f: &mut dyn FnMut(EntityId, &dyn project::Item),
|
||||
) {
|
||||
self.editor.for_each_project_item(cx, f)
|
||||
}
|
||||
|
||||
// fn is_singleton(&self, _: &AppContext) -> bool {
|
||||
// true
|
||||
// }
|
||||
fn is_singleton(&self, _: &AppContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// fn can_save(&self, _: &AppContext) -> bool {
|
||||
// true
|
||||
// }
|
||||
fn can_save(&self, _: &AppContext) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// fn save(
|
||||
// &mut self,
|
||||
// _: ModelHandle<Project>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Task<anyhow::Result<()>> {
|
||||
// self.submit(cx)
|
||||
// }
|
||||
fn save(
|
||||
&mut self,
|
||||
_project: Model<Project>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<anyhow::Result<()>> {
|
||||
self.submit(cx)
|
||||
}
|
||||
|
||||
// fn save_as(
|
||||
// &mut self,
|
||||
// _: ModelHandle<Project>,
|
||||
// _: std::path::PathBuf,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Task<anyhow::Result<()>> {
|
||||
// self.submit(cx)
|
||||
// }
|
||||
fn save_as(
|
||||
&mut self,
|
||||
_: Model<Project>,
|
||||
_: std::path::PathBuf,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<anyhow::Result<()>> {
|
||||
self.submit(cx)
|
||||
}
|
||||
|
||||
// fn reload(
|
||||
// &mut self,
|
||||
// _: ModelHandle<Project>,
|
||||
// _: &mut ViewContext<Self>,
|
||||
// ) -> Task<anyhow::Result<()>> {
|
||||
// Task::Ready(Some(Ok(())))
|
||||
// }
|
||||
fn reload(&mut self, _: Model<Project>, _: &mut ViewContext<Self>) -> Task<anyhow::Result<()>> {
|
||||
Task::Ready(Some(Ok(())))
|
||||
}
|
||||
|
||||
// fn clone_on_split(
|
||||
// &self,
|
||||
// _workspace_id: workspace::WorkspaceId,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Option<Self>
|
||||
// where
|
||||
// Self: Sized,
|
||||
// {
|
||||
// let buffer = self
|
||||
// .editor
|
||||
// .read(cx)
|
||||
// .buffer()
|
||||
// .read(cx)
|
||||
// .as_singleton()
|
||||
// .expect("Feedback buffer is only ever singleton");
|
||||
fn clone_on_split(
|
||||
&self,
|
||||
_workspace_id: workspace::WorkspaceId,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<View<Self>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let buffer = self
|
||||
.editor
|
||||
.read(cx)
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.as_singleton()
|
||||
.expect("Feedback buffer is only ever singleton");
|
||||
|
||||
// Some(Self::new(
|
||||
// self.system_specs.clone(),
|
||||
// self.project.clone(),
|
||||
// buffer.clone(),
|
||||
// cx,
|
||||
// ))
|
||||
// }
|
||||
Some(cx.build_view(|cx| {
|
||||
Self::new(
|
||||
self.system_specs.clone(),
|
||||
self.project.clone(),
|
||||
buffer.clone(),
|
||||
cx,
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
// fn as_searchable(&self, handle: &ViewHandle<Self>) -> Option<Box<dyn SearchableItemHandle>> {
|
||||
// Some(Box::new(handle.clone()))
|
||||
// }
|
||||
fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
|
||||
Some(Box::new(handle.clone()))
|
||||
}
|
||||
|
||||
// fn act_as_type<'a>(
|
||||
// &'a self,
|
||||
// type_id: TypeId,
|
||||
// self_handle: &'a ViewHandle<Self>,
|
||||
// _: &'a AppContext,
|
||||
// ) -> Option<&'a AnyViewHandle> {
|
||||
// if type_id == TypeId::of::<Self>() {
|
||||
// Some(self_handle)
|
||||
// } else if type_id == TypeId::of::<Editor>() {
|
||||
// Some(&self.editor)
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
fn act_as_type<'a>(
|
||||
&'a self,
|
||||
type_id: TypeId,
|
||||
self_handle: &'a View<Self>,
|
||||
cx: &'a AppContext,
|
||||
) -> Option<AnyView> {
|
||||
if type_id == TypeId::of::<Self>() {
|
||||
Some(self_handle.to_any())
|
||||
} else if type_id == TypeId::of::<Editor>() {
|
||||
Some(self.editor.to_any())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
|
||||
// Editor::to_item_events(event)
|
||||
// }
|
||||
// }
|
||||
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
||||
|
||||
// impl SearchableItem for FeedbackEditor {
|
||||
// type Match = Range<Anchor>;
|
||||
fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
||||
|
||||
// fn to_search_event(
|
||||
// &mut self,
|
||||
// event: &Self::Event,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Option<workspace::searchable::SearchEvent> {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.to_search_event(event, cx))
|
||||
// }
|
||||
fn navigate(&mut self, _: Box<dyn std::any::Any>, _: &mut ViewContext<Self>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.clear_matches(cx))
|
||||
// }
|
||||
fn tab_description(&self, _: usize, _: &AppContext) -> Option<ui::prelude::SharedString> {
|
||||
None
|
||||
}
|
||||
|
||||
// fn update_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.update_matches(matches, cx))
|
||||
// }
|
||||
fn set_nav_history(&mut self, _: workspace::ItemNavHistory, _: &mut ViewContext<Self>) {}
|
||||
|
||||
// fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.query_suggestion(cx))
|
||||
// }
|
||||
fn is_dirty(&self, _: &AppContext) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// fn activate_match(
|
||||
// &mut self,
|
||||
// index: usize,
|
||||
// matches: Vec<Self::Match>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.activate_match(index, matches, cx))
|
||||
// }
|
||||
fn has_conflict(&self, _: &AppContext) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
// fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
// self.editor
|
||||
// .update(cx, |e, cx| e.select_matches(matches, cx))
|
||||
// }
|
||||
// fn replace(&mut self, matches: &Self::Match, query: &SearchQuery, cx: &mut ViewContext<Self>) {
|
||||
// self.editor
|
||||
// .update(cx, |e, cx| e.replace(matches, query, cx));
|
||||
// }
|
||||
// fn find_matches(
|
||||
// &mut self,
|
||||
// query: Arc<project::search::SearchQuery>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Task<Vec<Self::Match>> {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.find_matches(query, cx))
|
||||
// }
|
||||
fn breadcrumb_location(&self) -> workspace::ToolbarItemLocation {
|
||||
workspace::ToolbarItemLocation::Hidden
|
||||
}
|
||||
|
||||
// fn active_match_index(
|
||||
// &mut self,
|
||||
// matches: Vec<Self::Match>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Option<usize> {
|
||||
// self.editor
|
||||
// .update(cx, |editor, cx| editor.active_match_index(matches, cx))
|
||||
// }
|
||||
// }
|
||||
fn breadcrumbs(
|
||||
&self,
|
||||
_theme: &theme::Theme,
|
||||
_cx: &AppContext,
|
||||
) -> Option<Vec<workspace::item::BreadcrumbText>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn added_to_workspace(&mut self, _workspace: &mut Workspace, _cx: &mut ViewContext<Self>) {}
|
||||
|
||||
fn serialized_item_kind() -> Option<&'static str> {
|
||||
Some("feedback")
|
||||
}
|
||||
|
||||
fn deserialize(
|
||||
_project: gpui::Model<Project>,
|
||||
_workspace: gpui::WeakView<Workspace>,
|
||||
_workspace_id: workspace::WorkspaceId,
|
||||
_item_id: workspace::ItemId,
|
||||
_cx: &mut ViewContext<workspace::Pane>,
|
||||
) -> Task<anyhow::Result<View<Self>>> {
|
||||
unimplemented!(
|
||||
"deserialize() must be implemented if serialized_item_kind() returns Some(_)"
|
||||
)
|
||||
}
|
||||
|
||||
fn show_toolbar(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn pixel_position_of_cursor(&self, _: &AppContext) -> Option<gpui::Point<gpui::Pixels>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<SearchEvent> for FeedbackEditor {}
|
||||
|
||||
impl SearchableItem for FeedbackEditor {
|
||||
type Match = Range<Anchor>;
|
||||
|
||||
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.clear_matches(cx))
|
||||
}
|
||||
|
||||
fn update_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.update_matches(matches, cx))
|
||||
}
|
||||
|
||||
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.query_suggestion(cx))
|
||||
}
|
||||
|
||||
fn activate_match(
|
||||
&mut self,
|
||||
index: usize,
|
||||
matches: Vec<Self::Match>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.activate_match(index, matches, cx))
|
||||
}
|
||||
|
||||
fn select_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||
self.editor
|
||||
.update(cx, |e, cx| e.select_matches(matches, cx))
|
||||
}
|
||||
fn replace(&mut self, matches: &Self::Match, query: &SearchQuery, cx: &mut ViewContext<Self>) {
|
||||
self.editor
|
||||
.update(cx, |e, cx| e.replace(matches, query, cx));
|
||||
}
|
||||
fn find_matches(
|
||||
&mut self,
|
||||
query: Arc<project::search::SearchQuery>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Vec<Self::Match>> {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.find_matches(query, cx))
|
||||
}
|
||||
|
||||
fn active_match_index(
|
||||
&mut self,
|
||||
matches: Vec<Self::Match>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<usize> {
|
||||
self.editor
|
||||
.update(cx, |editor, cx| editor.active_match_index(matches, cx))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,36 @@
|
|||
// use gpui::{
|
||||
// elements::{Flex, Label, MouseEventHandler, ParentElement, Text},
|
||||
// platform::{CursorStyle, MouseButton},
|
||||
// AnyElement, Element, Entity, View, ViewContext, ViewHandle,
|
||||
// };
|
||||
// use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};
|
||||
use gpui::{Div, EventEmitter, View, ViewContext};
|
||||
use ui::{prelude::*, Label};
|
||||
use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
||||
|
||||
// use crate::{feedback_editor::FeedbackEditor, open_zed_community_repo, OpenZedCommunityRepo};
|
||||
use crate::feedback_editor::FeedbackEditor;
|
||||
|
||||
// pub struct FeedbackInfoText {
|
||||
// active_item: Option<ViewHandle<FeedbackEditor>>,
|
||||
// }
|
||||
pub struct FeedbackInfoText {
|
||||
active_item: Option<View<FeedbackEditor>>,
|
||||
}
|
||||
|
||||
// impl FeedbackInfoText {
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// active_item: Default::default(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl FeedbackInfoText {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active_item: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Entity for FeedbackInfoText {
|
||||
// type Event = ();
|
||||
// }
|
||||
// TODO
|
||||
impl Render for FeedbackInfoText {
|
||||
type Element = Div;
|
||||
|
||||
fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
|
||||
// TODO - get this into the toolbar area like before - ensure things work the same when horizontally shrinking app
|
||||
div()
|
||||
.size_full()
|
||||
.child(Label::new("Share your feedback. Include your email for replies. For issues and discussions, visit the ").color(Color::Muted))
|
||||
.child(Label::new("community repo").color(Color::Muted)) // TODO - this needs to be a link
|
||||
.child(Label::new(".").color(Color::Muted))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - delete
|
||||
// impl View for FeedbackInfoText {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "FeedbackInfoText"
|
||||
|
@ -73,22 +81,25 @@
|
|||
// }
|
||||
// }
|
||||
|
||||
// impl ToolbarItemView for FeedbackInfoText {
|
||||
// fn set_active_pane_item(
|
||||
// &mut self,
|
||||
// active_pane_item: Option<&dyn ItemHandle>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> workspace::ToolbarItemLocation {
|
||||
// cx.notify();
|
||||
// if let Some(feedback_editor) = active_pane_item.and_then(|i| i.downcast::<FeedbackEditor>())
|
||||
// {
|
||||
// self.active_item = Some(feedback_editor);
|
||||
// ToolbarItemLocation::PrimaryLeft {
|
||||
// flex: Some((1., false)),
|
||||
// }
|
||||
// } else {
|
||||
// self.active_item = None;
|
||||
// ToolbarItemLocation::Hidden
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl EventEmitter<ToolbarItemEvent> for FeedbackInfoText {}
|
||||
|
||||
impl ToolbarItemView for FeedbackInfoText {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
active_pane_item: Option<&dyn ItemHandle>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> workspace::ToolbarItemLocation {
|
||||
cx.notify();
|
||||
|
||||
if let Some(feedback_editor) = active_pane_item.and_then(|i| i.downcast::<FeedbackEditor>())
|
||||
{
|
||||
dbg!("Editor");
|
||||
self.active_item = Some(feedback_editor);
|
||||
ToolbarItemLocation::PrimaryLeft
|
||||
} else {
|
||||
dbg!("no editor");
|
||||
self.active_item = None;
|
||||
ToolbarItemLocation::Hidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,112 +1,115 @@
|
|||
// use crate::{feedback_editor::SubmitFeedback, feedback_modal::FeedbackModal};
|
||||
// use anyhow::Result;
|
||||
// use gpui::{AppContext, Render, Task, View, ViewContext};
|
||||
// use ui::IconButton;
|
||||
// use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};
|
||||
use crate::feedback_editor::{FeedbackEditor, SubmitFeedback};
|
||||
use anyhow::Result;
|
||||
use gpui::{AppContext, Div, EventEmitter, Render, Task, View, ViewContext};
|
||||
use ui::prelude::*;
|
||||
use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
|
||||
|
||||
// pub fn init(cx: &mut AppContext) {
|
||||
// cx.add_async_action(SubmitFeedbackButton::submit);
|
||||
// }
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
// cx.add_action(SubmitFeedbackButton::submit);
|
||||
}
|
||||
|
||||
// pub struct SubmitFeedbackButton {
|
||||
// pub(crate) active_item: Option<View<FeedbackModal>>,
|
||||
// }
|
||||
pub struct SubmitFeedbackButton {
|
||||
pub(crate) active_item: Option<View<FeedbackEditor>>,
|
||||
}
|
||||
|
||||
// impl SubmitFeedbackButton {
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// active_item: Default::default(),
|
||||
// }
|
||||
// }
|
||||
impl SubmitFeedbackButton {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
active_item: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn submit(
|
||||
// &mut self,
|
||||
// _: &SubmitFeedback,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> Option<Task<Result<()>>> {
|
||||
// if let Some(active_item) = self.active_item.as_ref() {
|
||||
// Some(active_item.update(cx, |feedback_editor, cx| feedback_editor.submit(cx)))
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
pub fn submit(
|
||||
&mut self,
|
||||
_: &SubmitFeedback,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<Task<Result<()>>> {
|
||||
if let Some(active_item) = self.active_item.as_ref() {
|
||||
Some(active_item.update(cx, |feedback_editor, cx| feedback_editor.submit(cx)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
impl Render for SubmitFeedbackButton {
|
||||
type Element = Div;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let allow_submission = self
|
||||
.active_item
|
||||
.as_ref()
|
||||
.map_or(true, |i| i.read(cx).allow_submission);
|
||||
|
||||
div()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - delete
|
||||
// impl View for SubmitFeedbackButton {
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// let theme = theme::current(cx).clone();
|
||||
// let allow_submission = self
|
||||
// .active_item
|
||||
// .as_ref()
|
||||
// .map_or(true, |i| i.read(cx).allow_submission);
|
||||
|
||||
// enum SubmitFeedbackButton {}
|
||||
// MouseEventHandler::new::<SubmitFeedbackButton, _>(0, cx, |state, _| {
|
||||
// let text;
|
||||
// let style = if allow_submission {
|
||||
// text = "Submit as Markdown";
|
||||
// theme.feedback.submit_button.style_for(state)
|
||||
// } else {
|
||||
// text = "Submitting...";
|
||||
// theme
|
||||
// .feedback
|
||||
// .submit_button
|
||||
// .disabled
|
||||
// .as_ref()
|
||||
// .unwrap_or(&theme.feedback.submit_button.default)
|
||||
// };
|
||||
|
||||
// Label::new(text, style.text.clone())
|
||||
// .contained()
|
||||
// .with_style(style.container)
|
||||
// })
|
||||
// .with_cursor_style(CursorStyle::PointingHand)
|
||||
// .on_click(MouseButton::Left, |_, this, cx| {
|
||||
// this.submit(&Default::default(), cx);
|
||||
// })
|
||||
// .aligned()
|
||||
// .contained()
|
||||
// .with_margin_left(theme.feedback.button_margin)
|
||||
// .with_tooltip::<Self>(
|
||||
// 0,
|
||||
// "cmd-s",
|
||||
// Some(Box::new(SubmitFeedback)),
|
||||
// theme.tooltip.clone(),
|
||||
// cx,
|
||||
// )
|
||||
// .into_any()
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Render for SubmitFeedbackbutton {
|
||||
// type Element;
|
||||
impl EventEmitter<ToolbarItemEvent> for SubmitFeedbackButton {}
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
// todo!();
|
||||
// // IconButton::new("give-feedback", Icon::Envelope)
|
||||
// // .style(ui::ButtonStyle::Subtle)
|
||||
// // .on_click(|_, cx| cx.dispatch_action(GiveFeedback))
|
||||
// }
|
||||
// }
|
||||
|
||||
// // impl View for SubmitFeedbackButton {
|
||||
// // fn ui_name() -> &'static str {
|
||||
// // "SubmitFeedbackButton"
|
||||
// // }
|
||||
|
||||
// // fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// // let theme = theme::current(cx).clone();
|
||||
// // let allow_submission = self
|
||||
// // .active_item
|
||||
// // .as_ref()
|
||||
// // .map_or(true, |i| i.read(cx).allow_submission);
|
||||
|
||||
// // enum SubmitFeedbackButton {}
|
||||
// // MouseEventHandler::new::<SubmitFeedbackButton, _>(0, cx, |state, _| {
|
||||
// // let text;
|
||||
// // let style = if allow_submission {
|
||||
// // text = "Submit as Markdown";
|
||||
// // theme.feedback.submit_button.style_for(state)
|
||||
// // } else {
|
||||
// // text = "Submitting...";
|
||||
// // theme
|
||||
// // .feedback
|
||||
// // .submit_button
|
||||
// // .disabled
|
||||
// // .as_ref()
|
||||
// // .unwrap_or(&theme.feedback.submit_button.default)
|
||||
// // };
|
||||
|
||||
// // Label::new(text, style.text.clone())
|
||||
// // .contained()
|
||||
// // .with_style(style.container)
|
||||
// // })
|
||||
// // .with_cursor_style(CursorStyle::PointingHand)
|
||||
// // .on_click(MouseButton::Left, |_, this, cx| {
|
||||
// // this.submit(&Default::default(), cx);
|
||||
// // })
|
||||
// // .aligned()
|
||||
// // .contained()
|
||||
// // .with_margin_left(theme.feedback.button_margin)
|
||||
// // .with_tooltip::<Self>(
|
||||
// // 0,
|
||||
// // "cmd-s",
|
||||
// // Some(Box::new(SubmitFeedback)),
|
||||
// // theme.tooltip.clone(),
|
||||
// // cx,
|
||||
// // )
|
||||
// // .into_any()
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// impl ToolbarItemView for SubmitFeedbackButton {
|
||||
// fn set_active_pane_item(
|
||||
// &mut self,
|
||||
// active_pane_item: Option<&dyn ItemHandle>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) -> workspace::ToolbarItemLocation {
|
||||
// cx.notify();
|
||||
// if let Some(feedback_editor) = active_pane_item.and_then(|i| i.downcast::<FeedbackEditor>())
|
||||
// {
|
||||
// self.active_item = Some(feedback_editor);
|
||||
// ToolbarItemLocation::PrimaryRight { flex: None }
|
||||
// } else {
|
||||
// self.active_item = None;
|
||||
// ToolbarItemLocation::Hidden
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl ToolbarItemView for SubmitFeedbackButton {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
active_pane_item: Option<&dyn ItemHandle>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> workspace::ToolbarItemLocation {
|
||||
cx.notify();
|
||||
if let Some(feedback_editor) = active_pane_item.and_then(|i| i.downcast::<FeedbackEditor>())
|
||||
{
|
||||
self.active_item = Some(feedback_editor);
|
||||
ToolbarItemLocation::PrimaryRight
|
||||
} else {
|
||||
self.active_item = None;
|
||||
ToolbarItemLocation::Hidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ pub use assets::*;
|
|||
use breadcrumbs::Breadcrumbs;
|
||||
use collections::VecDeque;
|
||||
use editor::{Editor, MultiBuffer};
|
||||
use feedback::{
|
||||
feedback_info_text::FeedbackInfoText, submit_feedback_button::SubmitFeedbackButton,
|
||||
};
|
||||
use gpui::{
|
||||
actions, point, px, AppContext, Context, FocusableView, PromptLevel, TitlebarOptions,
|
||||
ViewContext, VisualContext, WindowBounds, WindowKind, WindowOptions,
|
||||
|
@ -110,11 +113,12 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
// toolbar.add_item(diagnostic_editor_controls, cx);
|
||||
// let project_search_bar = cx.add_view(|_| ProjectSearchBar::new());
|
||||
// toolbar.add_item(project_search_bar, cx);
|
||||
// let submit_feedback_button =
|
||||
// cx.build_view(|_| SubmitFeedbackButton::new());
|
||||
// toolbar.add_item(submit_feedback_button, cx);
|
||||
// let feedback_info_text = cx.add_view(|_| FeedbackInfoText::new());
|
||||
// toolbar.add_item(feedback_info_text, cx);
|
||||
let submit_feedback_button =
|
||||
cx.build_view(|_| SubmitFeedbackButton::new());
|
||||
// todo!(tool bar does not display or fire correctly right now, this is only stubbed in)
|
||||
toolbar.add_item(submit_feedback_button, cx);
|
||||
let feedback_info_text = cx.build_view(|_| FeedbackInfoText::new());
|
||||
toolbar.add_item(feedback_info_text, cx);
|
||||
// let lsp_log_item =
|
||||
// cx.add_view(|_| language_tools::LspLogToolbarItemView::new());
|
||||
// toolbar.add_item(lsp_log_item, cx);
|
||||
|
|
Loading…
Reference in a new issue