parent
84affa96ff
commit
1f611a9c90
10 changed files with 184 additions and 44 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -8044,6 +8044,7 @@ dependencies = [
|
||||||
"fuzzy",
|
"fuzzy",
|
||||||
"gpui",
|
"gpui",
|
||||||
"language",
|
"language",
|
||||||
|
"markdown",
|
||||||
"menu",
|
"menu",
|
||||||
"ordered-float 2.10.0",
|
"ordered-float 2.10.0",
|
||||||
"picker",
|
"picker",
|
||||||
|
@ -8051,9 +8052,7 @@ dependencies = [
|
||||||
"rpc",
|
"rpc",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
|
||||||
"smol",
|
"smol",
|
||||||
"theme",
|
|
||||||
"ui",
|
"ui",
|
||||||
"ui_text_field",
|
"ui_text_field",
|
||||||
"util",
|
"util",
|
||||||
|
|
|
@ -191,6 +191,12 @@
|
||||||
"ctrl-shift-enter": "editor::NewlineBelow"
|
"ctrl-shift-enter": "editor::NewlineBelow"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"context": "Markdown",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-c": "markdown::Copy"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"context": "AssistantPanel",
|
"context": "AssistantPanel",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
|
|
@ -207,6 +207,12 @@
|
||||||
"ctrl-shift-enter": "editor::NewlineBelow"
|
"ctrl-shift-enter": "editor::NewlineBelow"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"context": "Markdown",
|
||||||
|
"bindings": {
|
||||||
|
"cmd-c": "markdown::Copy"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"context": "AssistantPanel", // Used in the assistant crate, which we're replacing
|
"context": "AssistantPanel", // Used in the assistant crate, which we're replacing
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
|
|
@ -440,7 +440,7 @@ impl AssistantChat {
|
||||||
Markdown::new(
|
Markdown::new(
|
||||||
text,
|
text,
|
||||||
self.markdown_style.clone(),
|
self.markdown_style.clone(),
|
||||||
self.language_registry.clone(),
|
Some(self.language_registry.clone()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
@ -573,7 +573,7 @@ impl AssistantChat {
|
||||||
Markdown::new(
|
Markdown::new(
|
||||||
"".into(),
|
"".into(),
|
||||||
this.markdown_style.clone(),
|
this.markdown_style.clone(),
|
||||||
this.language_registry.clone(),
|
Some(this.language_registry.clone()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
@ -667,7 +667,7 @@ impl AssistantChat {
|
||||||
Markdown::new(
|
Markdown::new(
|
||||||
"".into(),
|
"".into(),
|
||||||
self.markdown_style.clone(),
|
self.markdown_style.clone(),
|
||||||
self.language_registry.clone(),
|
Some(self.language_registry.clone()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
@ -683,7 +683,7 @@ impl AssistantChat {
|
||||||
Markdown::new(
|
Markdown::new(
|
||||||
"".into(),
|
"".into(),
|
||||||
self.markdown_style.clone(),
|
self.markdown_style.clone(),
|
||||||
self.language_registry.clone(),
|
Some(self.language_registry.clone()),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -432,6 +432,19 @@ impl TextLayout {
|
||||||
pub fn line_height(&self) -> Pixels {
|
pub fn line_height(&self) -> Pixels {
|
||||||
self.0.lock().as_ref().unwrap().line_height
|
self.0.lock().as_ref().unwrap().line_height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// todo!()
|
||||||
|
pub fn text(&self) -> String {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.lines
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.text.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A text element that can be interacted with.
|
/// A text element that can be interacted with.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use assets::Assets;
|
use assets::Assets;
|
||||||
use gpui::{prelude::*, App, Task, View, WindowOptions};
|
use gpui::{prelude::*, App, KeyBinding, Task, View, WindowOptions};
|
||||||
use language::{language_settings::AllLanguageSettings, LanguageRegistry};
|
use language::{language_settings::AllLanguageSettings, LanguageRegistry};
|
||||||
use markdown::{Markdown, MarkdownStyle};
|
use markdown::{Markdown, MarkdownStyle};
|
||||||
use node_runtime::FakeNodeRuntime;
|
use node_runtime::FakeNodeRuntime;
|
||||||
|
@ -91,6 +91,7 @@ pub fn main() {
|
||||||
SettingsStore::update(cx, |store, cx| {
|
SettingsStore::update(cx, |store, cx| {
|
||||||
store.update_user_settings::<AllLanguageSettings>(cx, |_| {});
|
store.update_user_settings::<AllLanguageSettings>(cx, |_| {});
|
||||||
});
|
});
|
||||||
|
cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]);
|
||||||
|
|
||||||
let node_runtime = FakeNodeRuntime::new();
|
let node_runtime = FakeNodeRuntime::new();
|
||||||
let language_registry = Arc::new(LanguageRegistry::new(
|
let language_registry = Arc::new(LanguageRegistry::new(
|
||||||
|
@ -161,7 +162,7 @@ impl MarkdownExample {
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let markdown = cx.new_view(|cx| Markdown::new(text, style, language_registry, cx));
|
let markdown = cx.new_view(|cx| Markdown::new(text, style, Some(language_registry), cx));
|
||||||
Self { markdown }
|
Self { markdown }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@ mod parser;
|
||||||
use crate::parser::CodeBlockKind;
|
use crate::parser::CodeBlockKind;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
point, quad, AnyElement, AppContext, Bounds, CursorStyle, DispatchPhase, Edges, FocusHandle,
|
actions, point, quad, AnyElement, AppContext, Bounds, ClipboardItem, CursorStyle,
|
||||||
FocusableView, FontStyle, FontWeight, GlobalElementId, Hitbox, Hsla, KeyContext,
|
DispatchPhase, Edges, FocusHandle, FocusableView, FontStyle, FontWeight, GlobalElementId,
|
||||||
MouseDownEvent, MouseEvent, MouseMoveEvent, MouseUpEvent, Point, Render, StrikethroughStyle,
|
Hitbox, Hsla, KeyContext, MouseDownEvent, MouseEvent, MouseMoveEvent, MouseUpEvent, Point,
|
||||||
Style, StyledText, Task, TextLayout, TextRun, TextStyle, TextStyleRefinement, View,
|
Render, StrikethroughStyle, Style, StyledText, Task, TextLayout, TextRun, TextStyle,
|
||||||
|
TextStyleRefinement, View,
|
||||||
};
|
};
|
||||||
use language::{Language, LanguageRegistry, Rope};
|
use language::{Language, LanguageRegistry, Rope};
|
||||||
use parser::{parse_markdown, MarkdownEvent, MarkdownTag, MarkdownTagEnd};
|
use parser::{parse_markdown, MarkdownEvent, MarkdownTag, MarkdownTagEnd};
|
||||||
|
@ -37,14 +38,16 @@ pub struct Markdown {
|
||||||
should_reparse: bool,
|
should_reparse: bool,
|
||||||
pending_parse: Option<Task<Option<()>>>,
|
pending_parse: Option<Task<Option<()>>>,
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actions!(markdown, [Copy]);
|
||||||
|
|
||||||
impl Markdown {
|
impl Markdown {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
source: String,
|
source: String,
|
||||||
style: MarkdownStyle,
|
style: MarkdownStyle,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let focus_handle = cx.focus_handle();
|
let focus_handle = cx.focus_handle();
|
||||||
|
@ -83,6 +86,11 @@ impl Markdown {
|
||||||
&self.source
|
&self.source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy(&self, text: &RenderedText, cx: &mut ViewContext<Self>) {
|
||||||
|
let text = text.text_for_range(self.selection.start..self.selection.end);
|
||||||
|
cx.write_to_clipboard(ClipboardItem::new(text));
|
||||||
|
}
|
||||||
|
|
||||||
fn parse(&mut self, cx: &mut ViewContext<Self>) {
|
fn parse(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if self.source.is_empty() {
|
if self.source.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -191,14 +199,14 @@ impl Default for ParsedMarkdown {
|
||||||
pub struct MarkdownElement {
|
pub struct MarkdownElement {
|
||||||
markdown: View<Markdown>,
|
markdown: View<Markdown>,
|
||||||
style: MarkdownStyle,
|
style: MarkdownStyle,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MarkdownElement {
|
impl MarkdownElement {
|
||||||
fn new(
|
fn new(
|
||||||
markdown: View<Markdown>,
|
markdown: View<Markdown>,
|
||||||
style: MarkdownStyle,
|
style: MarkdownStyle,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Option<Arc<LanguageRegistry>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
markdown,
|
markdown,
|
||||||
|
@ -210,6 +218,7 @@ impl MarkdownElement {
|
||||||
fn load_language(&self, name: &str, cx: &mut WindowContext) -> Option<Arc<Language>> {
|
fn load_language(&self, name: &str, cx: &mut WindowContext) -> Option<Arc<Language>> {
|
||||||
let language = self
|
let language = self
|
||||||
.language_registry
|
.language_registry
|
||||||
|
.as_ref()?
|
||||||
.language_for_name(name)
|
.language_for_name(name)
|
||||||
.map(|language| language.ok())
|
.map(|language| language.ok())
|
||||||
.shared();
|
.shared();
|
||||||
|
@ -322,13 +331,21 @@ impl MarkdownElement {
|
||||||
match rendered_text.source_index_for_position(event.position) {
|
match rendered_text.source_index_for_position(event.position) {
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
|
let range = if event.click_count == 2 {
|
||||||
|
rendered_text.surrounding_word_range(source_index)
|
||||||
|
} else if event.click_count == 3 {
|
||||||
|
rendered_text.surrounding_line_range(source_index)
|
||||||
|
} else {
|
||||||
|
source_index..source_index
|
||||||
|
};
|
||||||
markdown.selection = Selection {
|
markdown.selection = Selection {
|
||||||
start: source_index,
|
start: range.start,
|
||||||
end: source_index,
|
end: range.end,
|
||||||
reversed: false,
|
reversed: false,
|
||||||
pending: true,
|
pending: true,
|
||||||
};
|
};
|
||||||
cx.focus(&markdown.focus_handle);
|
cx.focus(&markdown.focus_handle);
|
||||||
|
cx.prevent_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -378,6 +395,12 @@ impl MarkdownElement {
|
||||||
} else {
|
} else {
|
||||||
if markdown.selection.pending {
|
if markdown.selection.pending {
|
||||||
markdown.selection.pending = false;
|
markdown.selection.pending = false;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
let text = rendered_text
|
||||||
|
.text_for_range(markdown.selection.start..markdown.selection.end);
|
||||||
|
cx.write_to_primary(ClipboardItem::new(text))
|
||||||
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,6 +642,16 @@ impl Element for MarkdownElement {
|
||||||
let mut context = KeyContext::default();
|
let mut context = KeyContext::default();
|
||||||
context.add("Markdown");
|
context.add("Markdown");
|
||||||
cx.set_key_context(context);
|
cx.set_key_context(context);
|
||||||
|
let view = self.markdown.clone();
|
||||||
|
cx.on_action(std::any::TypeId::of::<crate::Copy>(), {
|
||||||
|
let text = rendered_markdown.text.clone();
|
||||||
|
move |_, phase, cx| {
|
||||||
|
let text = text.clone();
|
||||||
|
if phase == DispatchPhase::Bubble {
|
||||||
|
view.update(cx, move |this, cx| this.copy(&text, cx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
self.paint_mouse_listeners(hitbox, &rendered_markdown.text, cx);
|
self.paint_mouse_listeners(hitbox, &rendered_markdown.text, cx);
|
||||||
rendered_markdown.element.paint(cx);
|
rendered_markdown.element.paint(cx);
|
||||||
|
@ -920,6 +953,77 @@ impl RenderedText {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surrounding_word_range(&self, source_index: usize) -> Range<usize> {
|
||||||
|
for line in self.lines.iter() {
|
||||||
|
if source_index > line.source_end {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line_rendered_start = line.source_mappings.first().unwrap().rendered_index;
|
||||||
|
let rendered_index_in_line =
|
||||||
|
line.rendered_index_for_source_index(source_index) - line_rendered_start;
|
||||||
|
let text = line.layout.text();
|
||||||
|
let previous_space = if let Some(idx) = text[0..rendered_index_in_line].rfind(' ') {
|
||||||
|
idx + ' '.len_utf8()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let next_space = if let Some(idx) = text[rendered_index_in_line..].find(' ') {
|
||||||
|
rendered_index_in_line + idx
|
||||||
|
} else {
|
||||||
|
text.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
return line.source_index_for_rendered_index(line_rendered_start + previous_space)
|
||||||
|
..line.source_index_for_rendered_index(line_rendered_start + next_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
source_index..source_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn surrounding_line_range(&self, source_index: usize) -> Range<usize> {
|
||||||
|
for line in self.lines.iter() {
|
||||||
|
if source_index > line.source_end {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let line_source_start = line.source_mappings.first().unwrap().source_index;
|
||||||
|
return line_source_start..line.source_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
source_index..source_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_for_range(&self, range: Range<usize>) -> String {
|
||||||
|
let mut ret = vec![];
|
||||||
|
|
||||||
|
for line in self.lines.iter() {
|
||||||
|
if range.start > line.source_end {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let line_source_start = line.source_mappings.first().unwrap().source_index;
|
||||||
|
if range.end < line_source_start {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = line.layout.text();
|
||||||
|
|
||||||
|
let start = if range.start < line_source_start {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
line.rendered_index_for_source_index(range.start)
|
||||||
|
};
|
||||||
|
let end = if range.end > line.source_end {
|
||||||
|
line.rendered_index_for_source_index(line.source_end)
|
||||||
|
} else {
|
||||||
|
line.rendered_index_for_source_index(range.end)
|
||||||
|
}
|
||||||
|
.min(text.len());
|
||||||
|
|
||||||
|
ret.push(text[start..end].to_string());
|
||||||
|
}
|
||||||
|
ret.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
fn link_for_position(&self, position: Point<Pixels>) -> Option<&RenderedLink> {
|
fn link_for_position(&self, position: Point<Pixels>) -> Option<&RenderedLink> {
|
||||||
let source_index = self.source_index_for_position(position).ok()?;
|
let source_index = self.source_index_for_position(position).ok()?;
|
||||||
self.links
|
self.links
|
||||||
|
|
|
@ -102,7 +102,7 @@ pub struct EntryDetails {
|
||||||
is_processing: bool,
|
is_processing: bool,
|
||||||
is_cut: bool,
|
is_cut: bool,
|
||||||
git_status: Option<GitFileStatus>,
|
git_status: Option<GitFileStatus>,
|
||||||
is_dotenv: bool,
|
is_private: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Default, Debug, Deserialize)]
|
#[derive(PartialEq, Clone, Default, Debug, Deserialize)]
|
||||||
|
@ -1592,7 +1592,7 @@ impl ProjectPanel {
|
||||||
.clipboard_entry
|
.clipboard_entry
|
||||||
.map_or(false, |e| e.is_cut() && e.entry_id() == entry.id),
|
.map_or(false, |e| e.is_cut() && e.entry_id() == entry.id),
|
||||||
git_status: status,
|
git_status: status,
|
||||||
is_dotenv: entry.is_private,
|
is_private: entry.is_private,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(edit_state) = &self.edit_state {
|
if let Some(edit_state) = &self.edit_state {
|
||||||
|
|
|
@ -18,15 +18,14 @@ editor.workspace = true
|
||||||
feature_flags.workspace = true
|
feature_flags.workspace = true
|
||||||
fuzzy.workspace = true
|
fuzzy.workspace = true
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
|
markdown.workspace = true
|
||||||
menu.workspace = true
|
menu.workspace = true
|
||||||
ordered-float.workspace = true
|
ordered-float.workspace = true
|
||||||
picker.workspace = true
|
picker.workspace = true
|
||||||
dev_server_projects.workspace = true
|
dev_server_projects.workspace = true
|
||||||
rpc.workspace = true
|
rpc.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
settings.workspace = true
|
|
||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
theme.workspace = true
|
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
ui_text_field.workspace = true
|
ui_text_field.workspace = true
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
|
|
|
@ -10,12 +10,12 @@ use gpui::{
|
||||||
DismissEvent, EventEmitter, FocusHandle, FocusableView, Model, ScrollHandle, Transformation,
|
DismissEvent, EventEmitter, FocusHandle, FocusableView, Model, ScrollHandle, Transformation,
|
||||||
View, ViewContext,
|
View, ViewContext,
|
||||||
};
|
};
|
||||||
|
use markdown::Markdown;
|
||||||
|
use markdown::MarkdownStyle;
|
||||||
use rpc::{
|
use rpc::{
|
||||||
proto::{CreateDevServerResponse, DevServerStatus, RegenerateDevServerTokenResponse},
|
proto::{CreateDevServerResponse, DevServerStatus, RegenerateDevServerTokenResponse},
|
||||||
ErrorCode, ErrorExt,
|
ErrorCode, ErrorExt,
|
||||||
};
|
};
|
||||||
use settings::Settings;
|
|
||||||
use theme::ThemeSettings;
|
|
||||||
use ui::CheckboxWithLabel;
|
use ui::CheckboxWithLabel;
|
||||||
use ui::{prelude::*, Indicator, List, ListHeader, ListItem, ModalContent, ModalHeader, Tooltip};
|
use ui::{prelude::*, Indicator, List, ListHeader, ListItem, ModalContent, ModalHeader, Tooltip};
|
||||||
use ui_text_field::{FieldLabelLayout, TextField};
|
use ui_text_field::{FieldLabelLayout, TextField};
|
||||||
|
@ -33,6 +33,7 @@ pub struct DevServerProjects {
|
||||||
dev_server_name_input: View<TextField>,
|
dev_server_name_input: View<TextField>,
|
||||||
use_server_name_in_ssh: Selection,
|
use_server_name_in_ssh: Selection,
|
||||||
rename_dev_server_input: View<TextField>,
|
rename_dev_server_input: View<TextField>,
|
||||||
|
markdown: View<Markdown>,
|
||||||
_dev_server_subscription: Subscription,
|
_dev_server_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +114,23 @@ impl DevServerProjects {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let markdown_style = MarkdownStyle {
|
||||||
|
code_block: gpui::TextStyleRefinement {
|
||||||
|
font_family: Some("Zed Mono".into()),
|
||||||
|
color: Some(cx.theme().colors().editor_foreground),
|
||||||
|
background_color: Some(cx.theme().colors().editor_background),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
inline_code: Default::default(),
|
||||||
|
block_quote: Default::default(),
|
||||||
|
link: Default::default(),
|
||||||
|
rule_color: Default::default(),
|
||||||
|
block_quote_border_color: Default::default(),
|
||||||
|
syntax: cx.theme().syntax().clone(),
|
||||||
|
selection_background_color: cx.theme().players().local().selection,
|
||||||
|
};
|
||||||
|
let markdown = cx.new_view(|cx| Markdown::new("".to_string(), markdown_style, None, cx));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mode: Mode::Default(None),
|
mode: Mode::Default(None),
|
||||||
focus_handle,
|
focus_handle,
|
||||||
|
@ -121,6 +139,7 @@ impl DevServerProjects {
|
||||||
project_path_input,
|
project_path_input,
|
||||||
dev_server_name_input,
|
dev_server_name_input,
|
||||||
rename_dev_server_input,
|
rename_dev_server_input,
|
||||||
|
markdown,
|
||||||
use_server_name_in_ssh: Selection::Unselected,
|
use_server_name_in_ssh: Selection::Unselected,
|
||||||
_dev_server_subscription: subscription,
|
_dev_server_subscription: subscription,
|
||||||
}
|
}
|
||||||
|
@ -726,7 +745,7 @@ impl DevServerProjects {
|
||||||
.child(
|
.child(
|
||||||
CheckboxWithLabel::new(
|
CheckboxWithLabel::new(
|
||||||
"use-server-name-in-ssh",
|
"use-server-name-in-ssh",
|
||||||
Label::new("Use name as ssh connection string"),
|
Label::new("Use SSH for terminals"),
|
||||||
self.use_server_name_in_ssh,
|
self.use_server_name_in_ssh,
|
||||||
|&_, _| {}
|
|&_, _| {}
|
||||||
)
|
)
|
||||||
|
@ -748,7 +767,7 @@ impl DevServerProjects {
|
||||||
};
|
};
|
||||||
div.px_2().child(Label::new(format!(
|
div.px_2().child(Label::new(format!(
|
||||||
"Once you have created a dev server, you will be given a command to run on the server to register it.\n\n\
|
"Once you have created a dev server, you will be given a command to run on the server to register it.\n\n\
|
||||||
Ssh connection string enables remote terminals, which runs `ssh {ssh_host_name}` when creating terminal tabs."
|
If you enable SSH, then the terminal will automatically `ssh {ssh_host_name}` on open."
|
||||||
)))
|
)))
|
||||||
})
|
})
|
||||||
.when_some(dev_server.clone(), |div, dev_server| {
|
.when_some(dev_server.clone(), |div, dev_server| {
|
||||||
|
@ -758,7 +777,7 @@ impl DevServerProjects {
|
||||||
.dev_server_status(DevServerId(dev_server.dev_server_id));
|
.dev_server_status(DevServerId(dev_server.dev_server_id));
|
||||||
|
|
||||||
div.child(
|
div.child(
|
||||||
Self::render_dev_server_token_instructions(&dev_server.access_token, &dev_server.name, status, cx)
|
self.render_dev_server_token_instructions(&dev_server.access_token, &dev_server.name, status, cx)
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -766,12 +785,18 @@ impl DevServerProjects {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_dev_server_token_instructions(
|
fn render_dev_server_token_instructions(
|
||||||
|
&self,
|
||||||
access_token: &str,
|
access_token: &str,
|
||||||
dev_server_name: &str,
|
dev_server_name: &str,
|
||||||
status: DevServerStatus,
|
status: DevServerStatus,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Div {
|
) -> Div {
|
||||||
let instructions = SharedString::from(format!("zed --dev-server-token {}", access_token));
|
let instructions = SharedString::from(format!("zed --dev-server-token {}", access_token));
|
||||||
|
self.markdown.update(cx, |markdown, cx| {
|
||||||
|
if !markdown.source().contains(access_token) {
|
||||||
|
markdown.reset(format!("```\n{}\n```", instructions), cx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.pl_2()
|
.pl_2()
|
||||||
|
@ -799,19 +824,7 @@ impl DevServerProjects {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(v_flex().w_full().child(self.markdown.clone()))
|
||||||
v_flex()
|
|
||||||
.w_full()
|
|
||||||
.bg(cx.theme().colors().title_bar_background) // todo: this should be distinct
|
|
||||||
.border_1()
|
|
||||||
.border_color(cx.theme().colors().border_variant)
|
|
||||||
.rounded_md()
|
|
||||||
.my_1()
|
|
||||||
.py_0p5()
|
|
||||||
.px_3()
|
|
||||||
.font_family(ThemeSettings::get_global(cx).buffer_font.family.clone())
|
|
||||||
.child(Label::new(instructions)),
|
|
||||||
)
|
|
||||||
.when(status == DevServerStatus::Offline, |this| {
|
.when(status == DevServerStatus::Offline, |this| {
|
||||||
this.child(Self::render_loading_spinner("Waiting for connection…"))
|
this.child(Self::render_loading_spinner("Waiting for connection…"))
|
||||||
})
|
})
|
||||||
|
@ -926,14 +939,13 @@ impl DevServerProjects {
|
||||||
EditDevServerState::RegeneratingToken => {
|
EditDevServerState::RegeneratingToken => {
|
||||||
Self::render_loading_spinner("Generating token...")
|
Self::render_loading_spinner("Generating token...")
|
||||||
}
|
}
|
||||||
EditDevServerState::RegeneratedToken(response) => {
|
EditDevServerState::RegeneratedToken(response) => self
|
||||||
Self::render_dev_server_token_instructions(
|
.render_dev_server_token_instructions(
|
||||||
&response.access_token,
|
&response.access_token,
|
||||||
&dev_server_name,
|
&dev_server_name,
|
||||||
dev_server_status,
|
dev_server_status,
|
||||||
cx,
|
cx,
|
||||||
)
|
),
|
||||||
}
|
|
||||||
_ => h_flex().items_end().w_full().child(
|
_ => h_flex().items_end().w_full().child(
|
||||||
Button::new("regenerate-dev-server-token", "Generate new access token")
|
Button::new("regenerate-dev-server-token", "Generate new access token")
|
||||||
.icon(IconName::Update)
|
.icon(IconName::Update)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue