1use assets::Assets;
2use gpui::{prelude::*, rgb, Application, Entity, KeyBinding, StyleRefinement, WindowOptions};
3use language::{language_settings::AllLanguageSettings, LanguageRegistry};
4use markdown::{Markdown, MarkdownStyle};
5use node_runtime::NodeRuntime;
6use settings::SettingsStore;
7use std::sync::Arc;
8use theme::LoadThemes;
9use ui::prelude::*;
10use ui::{div, App, Window};
11
12const MARKDOWN_EXAMPLE: &str = r#"
13# Markdown Example Document
14
15## Headings
16Headings are created by adding one or more `#` symbols before your heading text. The number of `#` you use will determine the size of the heading.
17
18```rust
19gpui::window::ViewContext
20impl<'a, V> ViewContext<'a, V>
21pub fn on_blur(&mut self, handle: &FocusHandle, listener: impl FnMut(&mut V, &mut iewContext<V>) + 'static) -> Subscription
22where
23 // Bounds from impl:
24 V: 'static,
25```
26
27## Emphasis
28Emphasis can be added with italics or bold. *This text will be italic*. _This will also be italic_
29
30## Lists
31
32### Unordered Lists
33Unordered lists use asterisks `*`, plus `+`, or minus `-` as list markers.
34
35* Item 1
36* Item 2
37 * Item 2a
38 * Item 2b
39
40### Ordered Lists
41Ordered lists use numbers followed by a period.
42
431. Item 1
442. Item 2
453. Item 3
46 1. Item 3a
47 2. Item 3b
48
49## Links
50Links are created using the format [http://zed.dev](https://zed.dev).
51
52They can also be detected automatically, for example https://zed.dev/blog.
53
54They may contain dollar signs:
55
56[https://svelte.dev/docs/svelte/$state](https://svelte.dev/docs/svelte/$state)
57
58https://svelte.dev/docs/svelte/$state
59
60## Images
61Images are like links, but with an exclamation mark `!` in front.
62
63```markdown
64
65```
66
67## Code
68Inline `code` can be wrapped with backticks `` ` ``.
69
70```markdown
71Inline `code` has `back-ticks around` it.
72```
73
74Code blocks can be created by indenting lines by four spaces or with triple backticks ```.
75
76```javascript
77function test() {
78 console.log("notice the blank line before this function?");
79}
80```
81
82## Blockquotes
83Blockquotes are created with `>`.
84
85> This is a blockquote.
86
87## Horizontal Rules
88Horizontal rules are created using three or more asterisks `***`, dashes `---`, or underscores `___`.
89
90## Line breaks
91This is a
92\
93line break!
94
95---
96
97Remember, markdown processors may have slight differences and extensions, so always refer to the specific documentation or guides relevant to your platform or editor for the best practices and additional features.
98"#;
99
100pub fn main() {
101 env_logger::init();
102 Application::new().with_assets(Assets).run(|cx| {
103 let store = SettingsStore::test(cx);
104 cx.set_global(store);
105 language::init(cx);
106 SettingsStore::update(cx, |store, cx| {
107 store.update_user_settings::<AllLanguageSettings>(cx, |_| {});
108 });
109 cx.bind_keys([KeyBinding::new("cmd-c", markdown::Copy, None)]);
110
111 let node_runtime = NodeRuntime::unavailable();
112 theme::init(LoadThemes::JustBase, cx);
113
114 let language_registry = LanguageRegistry::new(cx.background_executor().clone());
115 language_registry.set_theme(cx.theme().clone());
116 let language_registry = Arc::new(language_registry);
117 languages::init(language_registry.clone(), node_runtime, cx);
118 Assets.load_fonts(cx).unwrap();
119
120 cx.activate(true);
121 cx.open_window(WindowOptions::default(), |window, cx| {
122 cx.new(|cx| {
123 let markdown_style = MarkdownStyle {
124 base_text_style: gpui::TextStyle {
125 font_family: "Zed Plex Sans".into(),
126 color: cx.theme().colors().terminal_ansi_black,
127 ..Default::default()
128 },
129 code_block: StyleRefinement::default()
130 .font_family("Zed Plex Mono")
131 .m(rems(1.))
132 .bg(rgb(0xAAAAAAA)),
133 inline_code: gpui::TextStyleRefinement {
134 font_family: Some("Zed Mono".into()),
135 color: Some(cx.theme().colors().editor_foreground),
136 background_color: Some(cx.theme().colors().editor_background),
137 ..Default::default()
138 },
139 rule_color: Color::Muted.color(cx),
140 block_quote_border_color: Color::Muted.color(cx),
141 block_quote: gpui::TextStyleRefinement {
142 color: Some(Color::Muted.color(cx)),
143 ..Default::default()
144 },
145 link: gpui::TextStyleRefinement {
146 color: Some(Color::Accent.color(cx)),
147 underline: Some(gpui::UnderlineStyle {
148 thickness: px(1.),
149 color: Some(Color::Accent.color(cx)),
150 wavy: false,
151 }),
152 ..Default::default()
153 },
154 syntax: cx.theme().syntax().clone(),
155 selection_background_color: {
156 let mut selection = cx.theme().players().local().selection;
157 selection.fade_out(0.7);
158 selection
159 },
160 ..Default::default()
161 };
162
163 MarkdownExample::new(
164 MARKDOWN_EXAMPLE.to_string(),
165 markdown_style,
166 language_registry,
167 window,
168 cx,
169 )
170 })
171 })
172 .unwrap();
173 });
174}
175
176struct MarkdownExample {
177 markdown: Entity<Markdown>,
178}
179
180impl MarkdownExample {
181 pub fn new(
182 text: String,
183 style: MarkdownStyle,
184 language_registry: Arc<LanguageRegistry>,
185 window: &mut Window,
186 cx: &mut App,
187 ) -> Self {
188 let markdown =
189 cx.new(|cx| Markdown::new(text, style, Some(language_registry), None, window, cx));
190 Self { markdown }
191 }
192}
193
194impl Render for MarkdownExample {
195 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
196 div()
197 .id("markdown-example")
198 .debug_selector(|| "foo".into())
199 .relative()
200 .bg(gpui::white())
201 .size_full()
202 .p_4()
203 .overflow_y_scroll()
204 .child(self.markdown.clone())
205 }
206}