Compare commits

..

1 Commits

Author SHA1 Message Date
Nate Butler
a48f2c6fcc CheckboxWithLabel -> ToggleWithLabel 2024-12-13 15:06:37 -05:00
31 changed files with 317 additions and 625 deletions

View File

@@ -8,7 +8,7 @@ on:
jobs:
update_top_ranking_issues:
runs-on: ubuntu-latest
if: github.repository == 'zed-industries/zed'
if: github.repository_owner == 'zed-industries'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up uv

View File

@@ -8,7 +8,7 @@ on:
jobs:
update_top_ranking_issues:
runs-on: ubuntu-latest
if: github.repository == 'zed-industries/zed'
if: github.repository_owner == 'zed-industries'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Set up uv

View File

@@ -140,7 +140,7 @@ jobs:
name: Create a Linux *.tar.gz bundle for ARM
if: github.repository_owner == 'zed-industries'
runs-on:
- buildjet-16vcpu-ubuntu-2204-arm
- hosted-linux-arm-1
needs: tests
env:
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}

5
Cargo.lock generated
View File

@@ -472,8 +472,6 @@ dependencies = [
"fuzzy",
"gpui",
"handlebars 4.5.0",
"html_to_markdown",
"http_client",
"indoc",
"language",
"language_model",
@@ -5182,17 +5180,14 @@ dependencies = [
"anyhow",
"collections",
"db",
"editor",
"git",
"gpui",
"language",
"project",
"schemars",
"serde",
"serde_derive",
"serde_json",
"settings",
"theme",
"ui",
"util",
"windows 0.58.0",

View File

@@ -12,7 +12,7 @@
"ctrl->": "zed::IncreaseBufferFontSize",
"ctrl-<": "zed::DecreaseBufferFontSize",
"ctrl-shift-j": "editor::JoinLines",
"ctrl-d": "editor::DuplicateSelection",
"ctrl-d": "editor::DuplicateLineDown",
"ctrl-y": "editor::DeleteLine",
"ctrl-m": "editor::ScrollCursorCenter",
"ctrl-pagedown": "editor::MovePageDown",

View File

@@ -15,7 +15,7 @@
"ctrl-shift-m": "editor::SelectLargerSyntaxNode",
"ctrl-shift-l": "editor::SplitSelectionIntoLines",
"ctrl-shift-a": "editor::SelectLargerSyntaxNode",
"ctrl-shift-d": "editor::DuplicateSelection",
"ctrl-shift-d": "editor::DuplicateLineDown",
"alt-f3": "editor::SelectAllMatches", // find_all_under
"f12": "editor::GoToDefinition",
"ctrl-f12": "editor::GoToDefinitionSplit",

View File

@@ -11,7 +11,7 @@
"ctrl->": "zed::IncreaseBufferFontSize",
"ctrl-<": "zed::DecreaseBufferFontSize",
"ctrl-shift-j": "editor::JoinLines",
"cmd-d": "editor::DuplicateSelection",
"cmd-d": "editor::DuplicateLineDown",
"cmd-backspace": "editor::DeleteLine",
"cmd-pagedown": "editor::MovePageDown",
"cmd-pageup": "editor::MovePageUp",

View File

@@ -18,7 +18,7 @@
"ctrl-shift-m": "editor::SelectLargerSyntaxNode",
"cmd-shift-l": "editor::SplitSelectionIntoLines",
"cmd-shift-a": "editor::SelectLargerSyntaxNode",
"cmd-shift-d": "editor::DuplicateSelection",
"cmd-shift-d": "editor::DuplicateLineDown",
"ctrl-cmd-g": "editor::SelectAllMatches", // find_all_under
"shift-f12": "editor::FindAllReferences",
"alt-cmd-down": "editor::GoToDefinition",

View File

@@ -56,7 +56,7 @@ use terminal_view::terminal_panel::TerminalPanel;
use text::{OffsetRangeExt, ToPoint as _};
use theme::ThemeSettings;
use ui::{
prelude::*, text_for_action, CheckboxWithLabel, IconButtonShape, KeyBinding, Popover, Tooltip,
prelude::*, text_for_action, ToggleWithLabel, IconButtonShape, KeyBinding, Popover, Tooltip,
};
use util::{RangeExt, ResultExt};
use workspace::{notifications::NotificationId, ItemHandle, Toast, Workspace};
@@ -2129,7 +2129,7 @@ impl PromptEditor {
.child(
h_flex()
.justify_between()
.child(CheckboxWithLabel::new(
.child(ToggleWithLabel::new(
"dont-show-again",
Label::new("Don't show again"),
if dismissed_rate_limit_notice() {

View File

@@ -31,8 +31,6 @@ futures.workspace = true
fuzzy.workspace = true
gpui.workspace = true
handlebars.workspace = true
html_to_markdown.workspace = true
http_client.workspace = true
language.workspace = true
language_model.workspace = true
language_model_selector.workspace = true

View File

@@ -23,5 +23,4 @@ pub struct Context {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ContextKind {
File,
FetchedUrl,
}

View File

@@ -1,4 +1,3 @@
mod fetch_context_picker;
mod file_context_picker;
use std::sync::Arc;
@@ -12,7 +11,6 @@ use ui::{prelude::*, ListItem, ListItemSpacing, Tooltip};
use util::ResultExt;
use workspace::Workspace;
use crate::context_picker::fetch_context_picker::FetchContextPicker;
use crate::context_picker::file_context_picker::FileContextPicker;
use crate::message_editor::MessageEditor;
@@ -20,7 +18,6 @@ use crate::message_editor::MessageEditor;
enum ContextPickerMode {
Default,
File(View<FileContextPicker>),
Fetch(View<FetchContextPicker>),
}
pub(super) struct ContextPicker {
@@ -50,7 +47,7 @@ impl ContextPicker {
icon: IconName::File,
},
ContextPickerEntry {
name: "fetch".into(),
name: "web".into(),
description: "Fetch content from URL".into(),
icon: IconName::Globe,
},
@@ -80,21 +77,16 @@ impl FocusableView for ContextPicker {
match &self.mode {
ContextPickerMode::Default => self.picker.focus_handle(cx),
ContextPickerMode::File(file_picker) => file_picker.focus_handle(cx),
ContextPickerMode::Fetch(fetch_picker) => fetch_picker.focus_handle(cx),
}
}
}
impl Render for ContextPicker {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
v_flex()
.w(px(400.))
.min_w(px(400.))
.map(|parent| match &self.mode {
ContextPickerMode::Default => parent.child(self.picker.clone()),
ContextPickerMode::File(file_picker) => parent.child(file_picker.clone()),
ContextPickerMode::Fetch(fetch_picker) => parent.child(fetch_picker.clone()),
})
v_flex().min_w(px(400.)).map(|parent| match &self.mode {
ContextPickerMode::Default => parent.child(self.picker.clone()),
ContextPickerMode::File(file_picker) => parent.child(file_picker.clone()),
})
}
}
@@ -152,16 +144,6 @@ impl PickerDelegate for ContextPickerDelegate {
)
}));
}
"fetch" => {
this.mode = ContextPickerMode::Fetch(cx.new_view(|cx| {
FetchContextPicker::new(
self.context_picker.clone(),
self.workspace.clone(),
self.message_editor.clone(),
cx,
)
}));
}
_ => {}
}
@@ -175,7 +157,7 @@ impl PickerDelegate for ContextPickerDelegate {
self.context_picker
.update(cx, |this, cx| match this.mode {
ContextPickerMode::Default => cx.emit(DismissEvent),
ContextPickerMode::File(_) | ContextPickerMode::Fetch(_) => {}
ContextPickerMode::File(_) => {}
})
.log_err();
}

View File

@@ -1,218 +0,0 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use anyhow::{bail, Context as _, Result};
use futures::AsyncReadExt as _;
use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakView};
use html_to_markdown::{convert_html_to_markdown, markdown, TagHandler};
use http_client::{AsyncBody, HttpClientWithUrl};
use picker::{Picker, PickerDelegate};
use ui::{prelude::*, ListItem, ListItemSpacing, ViewContext};
use workspace::Workspace;
use crate::context::ContextKind;
use crate::context_picker::ContextPicker;
use crate::message_editor::MessageEditor;
pub struct FetchContextPicker {
picker: View<Picker<FetchContextPickerDelegate>>,
}
impl FetchContextPicker {
pub fn new(
context_picker: WeakView<ContextPicker>,
workspace: WeakView<Workspace>,
message_editor: WeakView<MessageEditor>,
cx: &mut ViewContext<Self>,
) -> Self {
let delegate = FetchContextPickerDelegate::new(context_picker, workspace, message_editor);
let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx));
Self { picker }
}
}
impl FocusableView for FetchContextPicker {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
self.picker.focus_handle(cx)
}
}
impl Render for FetchContextPicker {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
self.picker.clone()
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
enum ContentType {
Html,
Plaintext,
Json,
}
pub struct FetchContextPickerDelegate {
context_picker: WeakView<ContextPicker>,
workspace: WeakView<Workspace>,
message_editor: WeakView<MessageEditor>,
url: String,
}
impl FetchContextPickerDelegate {
pub fn new(
context_picker: WeakView<ContextPicker>,
workspace: WeakView<Workspace>,
message_editor: WeakView<MessageEditor>,
) -> Self {
FetchContextPickerDelegate {
context_picker,
workspace,
message_editor,
url: String::new(),
}
}
async fn build_message(http_client: Arc<HttpClientWithUrl>, url: &str) -> Result<String> {
let mut url = url.to_owned();
if !url.starts_with("https://") && !url.starts_with("http://") {
url = format!("https://{url}");
}
let mut response = http_client.get(&url, AsyncBody::default(), true).await?;
let mut body = Vec::new();
response
.body_mut()
.read_to_end(&mut body)
.await
.context("error reading response body")?;
if response.status().is_client_error() {
let text = String::from_utf8_lossy(body.as_slice());
bail!(
"status error {}, response: {text:?}",
response.status().as_u16()
);
}
let Some(content_type) = response.headers().get("content-type") else {
bail!("missing Content-Type header");
};
let content_type = content_type
.to_str()
.context("invalid Content-Type header")?;
let content_type = match content_type {
"text/html" => ContentType::Html,
"text/plain" => ContentType::Plaintext,
"application/json" => ContentType::Json,
_ => ContentType::Html,
};
match content_type {
ContentType::Html => {
let mut handlers: Vec<TagHandler> = vec![
Rc::new(RefCell::new(markdown::WebpageChromeRemover)),
Rc::new(RefCell::new(markdown::ParagraphHandler)),
Rc::new(RefCell::new(markdown::HeadingHandler)),
Rc::new(RefCell::new(markdown::ListHandler)),
Rc::new(RefCell::new(markdown::TableHandler::new())),
Rc::new(RefCell::new(markdown::StyledTextHandler)),
];
if url.contains("wikipedia.org") {
use html_to_markdown::structure::wikipedia;
handlers.push(Rc::new(RefCell::new(wikipedia::WikipediaChromeRemover)));
handlers.push(Rc::new(RefCell::new(wikipedia::WikipediaInfoboxHandler)));
handlers.push(Rc::new(
RefCell::new(wikipedia::WikipediaCodeHandler::new()),
));
} else {
handlers.push(Rc::new(RefCell::new(markdown::CodeHandler)));
}
convert_html_to_markdown(&body[..], &mut handlers)
}
ContentType::Plaintext => Ok(std::str::from_utf8(&body)?.to_owned()),
ContentType::Json => {
let json: serde_json::Value = serde_json::from_slice(&body)?;
Ok(format!(
"```json\n{}\n```",
serde_json::to_string_pretty(&json)?
))
}
}
}
}
impl PickerDelegate for FetchContextPickerDelegate {
type ListItem = ListItem;
fn match_count(&self) -> usize {
1
}
fn selected_index(&self) -> usize {
0
}
fn set_selected_index(&mut self, _ix: usize, _cx: &mut ViewContext<Picker<Self>>) {}
fn placeholder_text(&self, _cx: &mut ui::WindowContext) -> Arc<str> {
"Enter a URL…".into()
}
fn update_matches(&mut self, query: String, _cx: &mut ViewContext<Picker<Self>>) -> Task<()> {
self.url = query;
Task::ready(())
}
fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext<Picker<Self>>) {
let Some(workspace) = self.workspace.upgrade() else {
return;
};
let http_client = workspace.read(cx).client().http_client().clone();
let url = self.url.clone();
cx.spawn(|this, mut cx| async move {
let text = Self::build_message(http_client, &url).await?;
this.update(&mut cx, |this, cx| {
this.delegate
.message_editor
.update(cx, |message_editor, _cx| {
message_editor.insert_context(ContextKind::FetchedUrl, url, text);
})
})??;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
fn dismissed(&mut self, cx: &mut ViewContext<Picker<Self>>) {
self.context_picker
.update(cx, |this, cx| {
this.reset_mode();
cx.emit(DismissEvent);
})
.ok();
}
fn render_match(
&self,
ix: usize,
selected: bool,
_cx: &mut ViewContext<Picker<Self>>,
) -> Option<Self::ListItem> {
Some(
ListItem::new(ix)
.inset(true)
.spacing(ListItemSpacing::Sparse)
.toggle_state(selected)
.child(self.url.clone()),
)
}
}

View File

@@ -245,7 +245,7 @@ impl PickerDelegate for FileContextPickerDelegate {
this.reset_mode();
cx.emit(DismissEvent);
})
.ok();
.log_err();
}
fn render_match(

View File

@@ -53,7 +53,7 @@ use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use text::{OffsetRangeExt, ToPoint as _};
use theme::ThemeSettings;
use ui::{prelude::*, CheckboxWithLabel, IconButtonShape, KeyBinding, Popover, Tooltip};
use ui::{prelude::*, ToggleWithLabel, IconButtonShape, KeyBinding, Popover, Tooltip};
use util::{RangeExt, ResultExt};
use workspace::{dock::Panel, ShowConfiguration};
use workspace::{notifications::NotificationId, ItemHandle, Toast, Workspace};
@@ -2061,7 +2061,7 @@ impl PromptEditor {
.child(
h_flex()
.justify_between()
.child(CheckboxWithLabel::new(
.child(ToggleWithLabel::new(
"dont-show-again",
Label::new("Don't show again"),
if dismissed_rate_limit_notice() {

View File

@@ -7,7 +7,7 @@ use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopove
use settings::Settings;
use theme::ThemeSettings;
use ui::{
prelude::*, ButtonLike, CheckboxWithLabel, ElevationIndex, IconButtonShape, KeyBinding,
prelude::*, ButtonLike, ToggleWithLabel, ElevationIndex, IconButtonShape, KeyBinding,
PopoverMenu, PopoverMenuHandle, Tooltip,
};
use workspace::Workspace;
@@ -262,7 +262,7 @@ impl Render for MessageEditor {
.child(
h_flex()
.justify_between()
.child(h_flex().gap_2().child(CheckboxWithLabel::new(
.child(h_flex().gap_2().child(ToggleWithLabel::new(
"use-tools",
Label::new("Tools"),
self.use_tools.into(),

View File

@@ -193,19 +193,12 @@ impl Thread {
if let Some(context) = self.context_for_message(message.id) {
let mut file_context = String::new();
let mut fetch_context = String::new();
for context in context.iter() {
match context.kind {
ContextKind::File => {
file_context.push_str(&context.text);
file_context.push('\n');
}
ContextKind::FetchedUrl => {
fetch_context.push_str(&context.name);
fetch_context.push('\n');
fetch_context.push_str(&context.text);
fetch_context.push('\n');
file_context.push_str("\n");
}
}
}
@@ -216,11 +209,6 @@ impl Thread {
context_text.push_str(&file_context);
}
if !fetch_context.is_empty() {
context_text.push_str("The following fetched results are available\n");
context_text.push_str(&fetch_context);
}
request_message
.content
.push(MessageContent::Text(context_text))

View File

@@ -11,7 +11,7 @@ use gpui::{
};
use picker::{Picker, PickerDelegate};
use std::sync::Arc;
use ui::{prelude::*, Avatar, CheckboxWithLabel, ContextMenu, ListItem, ListItemSpacing};
use ui::{prelude::*, Avatar, ToggleWithLabel, ContextMenu, ListItem, ListItemSpacing};
use util::TryFutureExt;
use workspace::{notifications::DetachAndPromptErr, ModalView};
@@ -155,7 +155,7 @@ impl Render for ChannelModal {
.h(rems_from_px(22.))
.justify_between()
.line_height(rems(1.25))
.child(CheckboxWithLabel::new(
.child(ToggleWithLabel::new(
"is-public",
Label::new("Public").size(LabelSize::Small),
if visibility == ChannelVisibility::Public {

View File

@@ -6135,7 +6135,29 @@ impl Editor {
});
}
pub fn duplicate(&mut self, upwards: bool, whole_lines: bool, cx: &mut ViewContext<Self>) {
pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot;
let selections = self.selections.all::<Point>(cx);
let mut edits = Vec::new();
for selection in selections.iter() {
let start = selection.start;
let end = selection.end;
let text = buffer.text_for_range(start..end).collect::<String>();
edits.push((selection.end..selection.end, text));
}
self.transact(cx, |this, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.edit(edits, None, cx);
});
this.request_autoscroll(Autoscroll::fit(), cx);
});
}
pub fn duplicate_line(&mut self, upwards: bool, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot;
let selections = self.selections.all::<Point>(cx);
@@ -6143,44 +6165,36 @@ impl Editor {
let mut edits = Vec::new();
let mut selections_iter = selections.iter().peekable();
while let Some(selection) = selections_iter.next() {
// Avoid duplicating the same lines twice.
let mut rows = selection.spanned_rows(false, &display_map);
// duplicate line-wise
if whole_lines || selection.start == selection.end {
// Avoid duplicating the same lines twice.
while let Some(next_selection) = selections_iter.peek() {
let next_rows = next_selection.spanned_rows(false, &display_map);
if next_rows.start < rows.end {
rows.end = next_rows.end;
selections_iter.next().unwrap();
} else {
break;
}
}
// Copy the text from the selected row region and splice it either at the start
// or end of the region.
let start = Point::new(rows.start.0, 0);
let end = Point::new(
rows.end.previous_row().0,
buffer.line_len(rows.end.previous_row()),
);
let text = buffer
.text_for_range(start..end)
.chain(Some("\n"))
.collect::<String>();
let insert_location = if upwards {
Point::new(rows.end.0, 0)
while let Some(next_selection) = selections_iter.peek() {
let next_rows = next_selection.spanned_rows(false, &display_map);
if next_rows.start < rows.end {
rows.end = next_rows.end;
selections_iter.next().unwrap();
} else {
start
};
edits.push((insert_location..insert_location, text));
} else {
// duplicate character-wise
let start = selection.start;
let end = selection.end;
let text = buffer.text_for_range(start..end).collect::<String>();
edits.push((selection.end..selection.end, text));
break;
}
}
// Copy the text from the selected row region and splice it either at the start
// or end of the region.
let start = Point::new(rows.start.0, 0);
let end = Point::new(
rows.end.previous_row().0,
buffer.line_len(rows.end.previous_row()),
);
let text = buffer
.text_for_range(start..end)
.chain(Some("\n"))
.collect::<String>();
let insert_location = if upwards {
Point::new(rows.end.0, 0)
} else {
start
};
edits.push((insert_location..insert_location, text));
}
self.transact(cx, |this, cx| {
@@ -6193,15 +6207,11 @@ impl Editor {
}
pub fn duplicate_line_up(&mut self, _: &DuplicateLineUp, cx: &mut ViewContext<Self>) {
self.duplicate(true, true, cx);
self.duplicate_line(true, cx);
}
pub fn duplicate_line_down(&mut self, _: &DuplicateLineDown, cx: &mut ViewContext<Self>) {
self.duplicate(false, true, cx);
}
pub fn duplicate_selection(&mut self, _: &DuplicateSelection, cx: &mut ViewContext<Self>) {
self.duplicate(false, false, cx);
self.duplicate_line(false, cx);
}
pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {

View File

@@ -5,7 +5,7 @@ use project::project_settings::{InlineBlameSettings, ProjectSettings};
use settings::{EditableSettingControl, Settings};
use theme::{FontFamilyCache, ThemeSettings};
use ui::{
prelude::*, CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer,
prelude::*, ToggleWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer,
SettingsGroup,
};
@@ -258,7 +258,7 @@ impl RenderOnce for BufferFontLigaturesControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
ToggleWithLabel::new(
"buffer-font-ligatures",
Label::new(self.name()),
value.into(),
@@ -311,7 +311,7 @@ impl RenderOnce for InlineGitBlameControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
ToggleWithLabel::new(
"inline-git-blame",
Label::new(self.name()),
value.into(),
@@ -364,7 +364,7 @@ impl RenderOnce for LineNumbersControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
ToggleWithLabel::new(
"line-numbers",
Label::new(self.name()),
value.into(),

View File

@@ -23,7 +23,7 @@ use project::DirectoryLister;
use release_channel::ReleaseChannel;
use settings::Settings;
use theme::ThemeSettings;
use ui::{prelude::*, CheckboxWithLabel, ContextMenu, PopoverMenu, ToggleButton, Tooltip};
use ui::{prelude::*, ToggleWithLabel, ContextMenu, PopoverMenu, ToggleButton, Tooltip};
use vim_mode_setting::VimModeSetting;
use workspace::{
item::{Item, ItemEvent},
@@ -994,7 +994,7 @@ impl ExtensionsPage {
.docs_url("https://zed.dev/docs/git#git-integrations"),
Feature::Vim => FeatureUpsell::new(telemetry, "Vim support is built-in to Zed!")
.docs_url("https://zed.dev/docs/vim")
.child(CheckboxWithLabel::new(
.child(ToggleWithLabel::new(
"enable-vim",
Label::new("Enable vim mode"),
if VimModeSetting::get_global(cx).0 {

View File

@@ -14,22 +14,19 @@ path = "src/git_ui.rs"
[dependencies]
anyhow.workspace = true
collections.workspace = true
db.workspace = true
editor.workspace = true
git.workspace = true
gpui.workspace = true
language.workspace = true
project.workspace = true
schemars.workspace = true
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
settings.workspace = true
theme.workspace = true
ui.workspace = true
util.workspace = true
workspace.workspace = true
git.workspace = true
collections.workspace = true
[target.'cfg(windows)'.dependencies]
windows.workspace = true

View File

@@ -1,7 +1,4 @@
use anyhow::Context;
use collections::HashMap;
use editor::Editor;
use language::Buffer;
use std::{
cell::OnceCell,
collections::HashSet,
@@ -11,7 +8,6 @@ use std::{
sync::Arc,
time::Duration,
};
use theme::ThemeSettings;
use git::repository::GitFileStatus;
@@ -28,7 +24,7 @@ use ui::{
use workspace::dock::{DockPosition, Panel, PanelEvent};
use workspace::Workspace;
use crate::{git_status_icon, settings::GitPanelSettings, GitState};
use crate::{git_status_icon, settings::GitPanelSettings};
use crate::{CommitAllChanges, CommitStagedChanges, DiscardAll, StageAll, UnstageAll};
actions!(git_panel, [ToggleFocus]);
@@ -88,8 +84,6 @@ pub struct GitPanel {
selected_item: Option<usize>,
show_scrollbar: bool,
expanded_dir_ids: HashMap<WorktreeId, Vec<ProjectEntryId>>,
git_state: Model<GitState>,
editor: View<Editor>,
// The entries that are currently shown in the panel, aka
// not hidden by folding or such
@@ -110,17 +104,11 @@ impl GitPanel {
}
pub fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> {
let git_state = GitState::get_global(cx);
let fs = workspace.app_state().fs.clone();
let weak_workspace = workspace.weak_handle();
let project = workspace.project().clone();
let language_registry = workspace.app_state().languages.clone();
let git_panel = cx.new_view(|cx: &mut ViewContext<Self>| {
let state = git_state.read(cx);
let current_commit_message = state.commit_message.clone();
let focus_handle = cx.focus_handle();
cx.on_focus(&focus_handle, Self::focus_in).detach();
cx.on_focus_out(&focus_handle, |this, _, cx| {
@@ -143,55 +131,6 @@ impl GitPanel {
})
.detach();
let editor = cx.new_view(|cx| {
let theme = ThemeSettings::get_global(cx);
let mut text_style = cx.text_style();
let refinement = TextStyleRefinement {
font_family: Some(theme.buffer_font.family.clone()),
font_features: Some(FontFeatures::disable_ligatures()),
font_size: Some(px(12.).into()),
color: Some(cx.theme().colors().editor_foreground),
background_color: Some(gpui::transparent_black()),
..Default::default()
};
text_style.refine(&refinement);
let mut editor = Editor::auto_height(10, cx);
if let Some(message) = current_commit_message {
editor.set_text(message, cx);
} else {
editor.set_text("", cx);
}
// editor.set_soft_wrap_mode(SoftWrap::EditorWidth, cx);
editor.set_use_autoclose(false);
editor.set_show_gutter(false, cx);
editor.set_show_wrap_guides(false, cx);
editor.set_show_indent_guides(false, cx);
editor.set_text_style_refinement(refinement);
editor.set_placeholder_text("Enter commit message", cx);
editor
});
let buffer = editor
.read(cx)
.buffer()
.read(cx)
.as_singleton()
.expect("commit editor must be singleton");
cx.subscribe(&buffer, Self::on_buffer_event).detach();
let markdown = language_registry.language_for_name("Markdown");
cx.spawn(|_, mut cx| async move {
let markdown = markdown.await.context("failed to load Markdown language")?;
buffer.update(&mut cx, |buffer, cx| {
buffer.set_language(Some(markdown), cx)
})
})
.detach_and_log_err(cx);
let scroll_handle = UniformListScrollHandle::new();
let mut this = Self {
@@ -203,8 +142,6 @@ impl GitPanel {
visible_entries: Vec::new(),
current_modifiers: cx.modifiers(),
expanded_dir_ids: Default::default(),
git_state,
editor,
width: Some(px(360.)),
scrollbar_state: ScrollbarState::new(scroll_handle.clone()).parent_view(cx.view()),
@@ -251,12 +188,12 @@ impl GitPanel {
}
fn should_show_scrollbar(_cx: &AppContext) -> bool {
// TODO: plug into settings
// todo!(): plug into settings
true
}
fn should_autohide_scrollbar(_cx: &AppContext) -> bool {
// TODO: plug into settings
// todo!(): plug into settings
true
}
@@ -318,44 +255,34 @@ impl GitPanel {
impl GitPanel {
fn stage_all(&mut self, _: &StageAll, _cx: &mut ViewContext<Self>) {
// TODO: Implement stage all
// todo!(): Implement stage all
println!("Stage all triggered");
}
fn unstage_all(&mut self, _: &UnstageAll, _cx: &mut ViewContext<Self>) {
// TODO: Implement unstage all
// todo!(): Implement unstage all
println!("Unstage all triggered");
}
fn discard_all(&mut self, _: &DiscardAll, _cx: &mut ViewContext<Self>) {
// TODO: Implement discard all
// todo!(): Implement discard all
println!("Discard all triggered");
}
fn clear_message(&mut self, cx: &mut ViewContext<Self>) {
let git_state = self.git_state.clone();
git_state.update(cx, |state, _cx| state.clear_message());
self.editor.update(cx, |editor, cx| editor.set_text("", cx));
}
/// Commit all staged changes
fn commit_staged_changes(&mut self, _: &CommitStagedChanges, cx: &mut ViewContext<Self>) {
self.clear_message(cx);
// TODO: Implement commit all staged
fn commit_staged_changes(&mut self, _: &CommitStagedChanges, _cx: &mut ViewContext<Self>) {
// todo!(): Implement commit all staged
println!("Commit staged changes triggered");
}
/// Commit all changes, regardless of whether they are staged or not
fn commit_all_changes(&mut self, _: &CommitAllChanges, cx: &mut ViewContext<Self>) {
self.clear_message(cx);
// TODO: Implement commit all changes
fn commit_all_changes(&mut self, _: &CommitAllChanges, _cx: &mut ViewContext<Self>) {
// todo!(): Implement commit all changes
println!("Commit all changes triggered");
}
fn all_staged(&self) -> bool {
// TODO: Implement all_staged
// todo!(): Implement all_staged
true
}
@@ -451,7 +378,7 @@ impl GitPanel {
}
}
// TODO: Update expanded directory state
// todo!(): Update expanded directory state
fn update_visible_entries(
&mut self,
new_selected_entry: Option<(WorktreeId, ProjectEntryId)>,
@@ -499,23 +426,6 @@ impl GitPanel {
cx.notify();
}
fn on_buffer_event(
&mut self,
_buffer: Model<Buffer>,
event: &language::BufferEvent,
cx: &mut ViewContext<Self>,
) {
if let language::BufferEvent::Reparsed | language::BufferEvent::Edited = event {
let commit_message = self.editor.update(cx, |editor, cx| editor.text(cx));
self.git_state.update(cx, |state, _cx| {
state.commit_message = Some(commit_message.into());
});
cx.notify();
}
}
}
impl GitPanel {
@@ -589,13 +499,6 @@ impl GitPanel {
}
pub fn render_commit_editor(&self, cx: &ViewContext<Self>) -> impl IntoElement {
let git_state = self.git_state.clone();
let commit_message = git_state.read(cx).commit_message.clone();
let editor = self.editor.clone();
let editor_focus_handle = editor.read(cx).focus_handle(cx).clone();
println!("{:?}", commit_message);
let focus_handle_1 = self.focus_handle(cx).clone();
let focus_handle_2 = self.focus_handle(cx).clone();
@@ -631,26 +534,25 @@ impl GitPanel {
div().w_full().h(px(140.)).px_2().pt_1().pb_2().child(
v_flex()
.id("commit-editor-container")
.relative()
.h_full()
.py_2p5()
.px_3()
.bg(cx.theme().colors().editor_background)
.on_click(cx.listener(move |_, _: &ClickEvent, cx| cx.focus(&editor_focus_handle)))
.child(self.editor.clone())
.child(
h_flex()
.absolute()
.bottom_2p5()
.right_3()
.child(div().gap_1().flex_grow())
.child(if self.current_modifiers.alt {
commit_all_button
} else {
commit_staged_button
}),
),
.font_buffer(cx)
.text_ui_sm(cx)
.text_color(cx.theme().colors().text_muted)
.child("Add a message")
.gap_1()
.child(div().flex_grow())
.child(h_flex().child(div().gap_1().flex_grow()).child(
if self.current_modifiers.alt {
commit_all_button
} else {
commit_staged_button
},
))
.cursor(CursorStyle::OperationNotAllowed)
.opacity(0.5),
)
}

View File

@@ -1,8 +1,8 @@
use ::settings::Settings;
use git::repository::GitFileStatus;
use gpui::{actions, prelude::*, AppContext, Global, Hsla, Model};
use gpui::{actions, AppContext, Hsla};
use settings::GitPanelSettings;
use ui::{Color, Icon, IconName, IntoElement, SharedString};
use ui::{Color, Icon, IconName, IntoElement};
pub mod git_panel;
mod settings;
@@ -14,50 +14,14 @@ actions!(
UnstageAll,
DiscardAll,
CommitStagedChanges,
CommitAllChanges,
ClearMessage
CommitAllChanges
]
);
pub fn init(cx: &mut AppContext) {
GitPanelSettings::register(cx);
let git_state = cx.new_model(|_cx| GitState::new());
cx.set_global(GlobalGitState(git_state));
}
struct GlobalGitState(Model<GitState>);
impl Global for GlobalGitState {}
pub struct GitState {
commit_message: Option<SharedString>,
}
impl GitState {
pub fn new() -> Self {
GitState {
commit_message: None,
}
}
pub fn set_message(&mut self, message: Option<SharedString>) {
self.commit_message = message;
}
pub fn clear_message(&mut self) {
self.commit_message = None;
}
pub fn get_global(cx: &mut AppContext) -> Model<GitState> {
cx.global::<GlobalGitState>().0.clone()
}
}
// impl EventEmitter<Event> for GitState {}
// #[derive(Clone, Debug, PartialEq, Eq)]
// pub enum Event {}
const ADDED_COLOR: Hsla = Hsla {
h: 142. / 360.,
s: 0.68,
@@ -77,7 +41,7 @@ const REMOVED_COLOR: Hsla = Hsla {
a: 1.0,
};
// TODO: Add updated status colors to theme
// todo!(): Add updated status colors to theme
pub fn git_status_icon(status: GitFileStatus) -> impl IntoElement {
match status {
GitFileStatus::Added => Icon::new(IconName::SquarePlus).color(Color::Custom(ADDED_COLOR)),

View File

@@ -315,10 +315,7 @@ impl ContextProvider for PythonContextProvider {
toolchains
.active_toolchain(worktree_id, "Python".into(), &mut cx)
.await
.map_or_else(
|| "python3".to_owned(),
|toolchain| format!("\"{}\"", toolchain.path),
)
.map_or_else(|| "python3".to_owned(), |toolchain| toolchain.path.into())
} else {
String::from("python3")
};
@@ -339,17 +336,14 @@ impl ContextProvider for PythonContextProvider {
TaskTemplate {
label: "execute selection".to_owned(),
command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(),
args: vec![
"-c".to_owned(),
VariableName::SelectedText.template_value_with_whitespace(),
],
args: vec!["-c".to_owned(), VariableName::SelectedText.template_value()],
..TaskTemplate::default()
},
// Execute an entire file
TaskTemplate {
label: format!("run '{}'", VariableName::File.template_value()),
command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(),
args: vec![VariableName::File.template_value_with_whitespace()],
args: vec![VariableName::File.template_value()],
..TaskTemplate::default()
},
];
@@ -364,7 +358,7 @@ impl ContextProvider for PythonContextProvider {
args: vec![
"-m".to_owned(),
"unittest".to_owned(),
VariableName::File.template_value_with_whitespace(),
VariableName::File.template_value(),
],
..TaskTemplate::default()
},
@@ -375,7 +369,7 @@ impl ContextProvider for PythonContextProvider {
args: vec![
"-m".to_owned(),
"unittest".to_owned(),
PYTHON_TEST_TARGET_TASK_VARIABLE.template_value_with_whitespace()
"$ZED_CUSTOM_PYTHON_TEST_TARGET".to_owned(),
],
tags: vec![
"python-unittest-class".to_owned(),
@@ -394,7 +388,7 @@ impl ContextProvider for PythonContextProvider {
args: vec![
"-m".to_owned(),
"pytest".to_owned(),
VariableName::File.template_value_with_whitespace(),
VariableName::File.template_value(),
],
..TaskTemplate::default()
},
@@ -405,7 +399,7 @@ impl ContextProvider for PythonContextProvider {
args: vec![
"-m".to_owned(),
"pytest".to_owned(),
PYTHON_TEST_TARGET_TASK_VARIABLE.template_value_with_whitespace(),
"$ZED_CUSTOM_PYTHON_TEST_TARGET".to_owned(),
],
tags: vec![
"python-pytest-class".to_owned(),

View File

@@ -4,7 +4,7 @@ use gpui::{AppContext, FontFeatures, FontWeight};
use settings::{EditableSettingControl, Settings};
use theme::{FontFamilyCache, SystemAppearance, ThemeMode, ThemeRegistry, ThemeSettings};
use ui::{
prelude::*, CheckboxWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer,
prelude::*, ToggleWithLabel, ContextMenu, DropdownMenu, NumericStepper, SettingsContainer,
SettingsGroup, ToggleButton,
};
@@ -368,7 +368,7 @@ impl RenderOnce for UiFontLigaturesControl {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
let value = Self::read(cx);
CheckboxWithLabel::new(
ToggleWithLabel::new(
"ui-font-ligatures",
Label::new(self.name()),
value.into(),

View File

@@ -135,10 +135,6 @@ impl VariableName {
pub fn template_value(&self) -> String {
format!("${self}")
}
/// Generates a `"$VARIABLE"`-like string, to be used instead of `Self::template_value` when expanded value could contain spaces or special characters.
pub fn template_value_with_whitespace(&self) -> String {
format!("\"${self}\"")
}
}
impl FromStr for VariableName {

View File

@@ -17,6 +17,38 @@ pub fn switch(id: impl Into<ElementId>, toggle_state: ToggleState) -> Switch {
Switch::new(id, toggle_state)
}
/// Creates a new checkbox with a label
///
/// [`ToggleWithLabel`] with [`ToggleKind::Checkbox`]
pub fn labeled_checkbox(
id: impl Into<ElementId>,
label: Label,
toggle_state: ToggleState,
on_click: impl Fn(&ToggleState, &mut WindowContext) + 'static,
) -> ToggleWithLabel {
ToggleWithLabel::new(id, label, toggle_state, on_click).kind(ToggleKind::Checkbox)
}
/// Creates a new switch with a label
///
/// [`ToggleWithLabel`] with [`ToggleKind::Switch`]
pub fn labeled_switch(
id: impl Into<ElementId>,
label: Label,
toggle_state: ToggleState,
on_click: impl Fn(&ToggleState, &mut WindowContext) + 'static,
) -> ToggleWithLabel {
ToggleWithLabel::new(id, label, toggle_state, on_click).kind(ToggleKind::Switch)
}
/// The types of toggles, defaulting to [`Checkbox`]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ToggleKind {
#[default]
Checkbox,
Switch,
}
/// # Checkbox
///
/// Checkboxes are used for multiple choices, not for mutually exclusive choices.
@@ -132,14 +164,15 @@ impl RenderOnce for Checkbox {
/// A [`Checkbox`] that has a [`Label`].
#[derive(IntoElement)]
pub struct CheckboxWithLabel {
pub struct ToggleWithLabel {
id: ElementId,
label: Label,
kind: ToggleKind,
checked: ToggleState,
on_click: Arc<dyn Fn(&ToggleState, &mut WindowContext) + 'static>,
}
impl CheckboxWithLabel {
impl ToggleWithLabel {
pub fn new(
id: impl Into<ElementId>,
label: Label,
@@ -149,22 +182,38 @@ impl CheckboxWithLabel {
Self {
id: id.into(),
label,
kind: ToggleKind::default(),
checked,
on_click: Arc::new(on_click),
}
}
pub fn kind(mut self, kind: ToggleKind) -> Self {
self.kind = kind;
self
}
}
impl RenderOnce for CheckboxWithLabel {
impl RenderOnce for ToggleWithLabel {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
h_flex()
.gap(DynamicSpacing::Base08.rems(cx))
.child(Checkbox::new(self.id.clone(), self.checked).on_click({
let on_click = self.on_click.clone();
move |checked, cx| {
(on_click)(checked, cx);
}
}))
.when(self.kind == ToggleKind::Checkbox, |this| {
this.child(Checkbox::new(self.id.clone(), self.checked).on_click({
let on_click = self.on_click.clone();
move |checked, cx| {
(on_click)(checked, cx);
}
}))
})
.when(self.kind == ToggleKind::Switch, |this| {
this.child(Switch::new(self.id.clone(), self.checked).on_click({
let on_click = self.on_click.clone();
move |checked, cx| {
(on_click)(checked, cx);
}
}))
})
.child(
div()
.id(SharedString::from(format!("{}-label", self.id)))
@@ -370,40 +419,70 @@ impl ComponentPreview for Switch {
}
}
impl ComponentPreview for CheckboxWithLabel {
impl ComponentPreview for ToggleWithLabel {
fn description() -> impl Into<Option<&'static str>> {
"A checkbox with an associated label, allowing users to select an option while providing a descriptive text."
"A toggle with an associated label, allowing users to select an option while providing a descriptive text. By default, the toggle is presented as a checkbox, but can also render a switch."
}
fn examples(_: &mut WindowContext) -> Vec<ComponentExampleGroup<Self>> {
vec![example_group(vec![
single_example(
"Unselected",
CheckboxWithLabel::new(
"checkbox_with_label_unselected",
Label::new("Always save on quit"),
ToggleState::Unselected,
|_, _| {},
),
vec![
example_group_with_title(
"Checkbox",
vec![
single_example(
"Unselected",
ToggleWithLabel::new(
"checkbox_with_label_unselected",
Label::new("Always save on quit"),
ToggleState::Unselected,
|_, _| {},
),
),
single_example(
"Indeterminate",
ToggleWithLabel::new(
"checkbox_with_label_indeterminate",
Label::new("Always save on quit"),
ToggleState::Indeterminate,
|_, _| {},
),
),
single_example(
"Selected",
ToggleWithLabel::new(
"checkbox_with_label_selected",
Label::new("Always save on quit"),
ToggleState::Selected,
|_, _| {},
),
),
],
),
single_example(
"Indeterminate",
CheckboxWithLabel::new(
"checkbox_with_label_indeterminate",
Label::new("Always save on quit"),
ToggleState::Indeterminate,
|_, _| {},
),
example_group_with_title(
"Switch",
vec![
single_example(
"Off",
ToggleWithLabel::new(
"switch_with_label_off",
Label::new("Dark mode"),
ToggleState::Unselected,
|_, _| {},
)
.kind(ToggleKind::Switch),
),
single_example(
"On",
ToggleWithLabel::new(
"switch_with_label_on",
Label::new("Dark mode"),
ToggleState::Selected,
|_, _| {},
)
.kind(ToggleKind::Switch),
),
],
),
single_example(
"Selected",
CheckboxWithLabel::new(
"checkbox_with_label_selected",
Label::new("Always save on quit"),
ToggleState::Selected,
|_, _| {},
),
),
])]
]
}
}

View File

@@ -11,7 +11,7 @@ use gpui::{
};
use settings::{Settings, SettingsStore};
use std::sync::Arc;
use ui::{prelude::*, CheckboxWithLabel, Tooltip};
use ui::{labeled_checkbox, prelude::*, Tooltip};
use vim_mode_setting::VimModeSetting;
use workspace::{
dock::DockPosition,
@@ -269,24 +269,26 @@ impl Render for WelcomePage {
.child(
h_flex()
.justify_between()
.child(CheckboxWithLabel::new(
"enable-vim",
Label::new("Enable Vim Mode"),
if VimModeSetting::get_global(cx).0 {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry
.report_app_event("welcome page: toggle vim".to_string());
this.update_settings::<VimModeSetting>(
selection,
cx,
|setting, value| *setting = Some(value),
);
}),
))
.child(
labeled_checkbox(
"enable-vim",
Label::new("Enable Vim Mode"),
if VimModeSetting::get_global(cx).0 {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry
.report_app_event("welcome page: toggle vim".to_string());
this.update_settings::<VimModeSetting>(
selection,
cx,
|setting, value| *setting = Some(value),
);
})
)
)
.child(
IconButton::new("vim-mode", IconName::Info)
.icon_size(IconSize::XSmall)
@@ -294,58 +296,62 @@ impl Render for WelcomePage {
.tooltip(|cx| Tooltip::text("You can also toggle Vim Mode via the command palette or Editor Controls menu.", cx)),
)
)
.child(CheckboxWithLabel::new(
"enable-crash",
Label::new("Send Crash Reports"),
if TelemetrySettings::get_global(cx).diagnostics {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry.report_app_event(
"welcome page: toggle diagnostic telemetry".to_string(),
);
this.update_settings::<TelemetrySettings>(selection, cx, {
let telemetry = this.telemetry.clone();
.child(
labeled_checkbox(
"enable-crash",
Label::new("Send Crash Reports"),
if TelemetrySettings::get_global(cx).diagnostics {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry.report_app_event(
"welcome page: toggle diagnostic telemetry".to_string(),
);
this.update_settings::<TelemetrySettings>(selection, cx, {
let telemetry = this.telemetry.clone();
move |settings, value| {
settings.diagnostics = Some(value);
move |settings, value| {
settings.diagnostics = Some(value);
telemetry.report_setting_event(
"diagnostic telemetry",
value.to_string(),
);
}
});
}),
))
.child(CheckboxWithLabel::new(
"enable-telemetry",
Label::new("Send Telemetry"),
if TelemetrySettings::get_global(cx).metrics {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry.report_app_event(
"welcome page: toggle metric telemetry".to_string(),
);
this.update_settings::<TelemetrySettings>(selection, cx, {
let telemetry = this.telemetry.clone();
telemetry.report_setting_event(
"diagnostic telemetry",
value.to_string(),
);
}
});
})
)
)
.child(
labeled_checkbox(
"enable-telemetry",
Label::new("Send Telemetry"),
if TelemetrySettings::get_global(cx).metrics {
ui::ToggleState::Selected
} else {
ui::ToggleState::Unselected
},
cx.listener(move |this, selection, cx| {
this.telemetry.report_app_event(
"welcome page: toggle metric telemetry".to_string(),
);
this.update_settings::<TelemetrySettings>(selection, cx, {
let telemetry = this.telemetry.clone();
move |settings, value| {
settings.metrics = Some(value);
move |settings, value| {
settings.metrics = Some(value);
telemetry.report_setting_event(
"metric telemetry",
value.to_string(),
);
}
});
}),
)),
telemetry.report_setting_event(
"metric telemetry",
value.to_string(),
);
}
});
})
)
),
),
)
}

View File

@@ -5,8 +5,8 @@ use theme::all_theme_colors;
use ui::{
element_cell, prelude::*, string_cell, utils::calculate_contrast_ratio, AudioStatus,
Availability, Avatar, AvatarAudioStatusIndicator, AvatarAvailabilityIndicator, ButtonLike,
Checkbox, CheckboxWithLabel, ContentGroup, DecoratedIcon, ElevationIndex, Facepile,
IconDecoration, Indicator, Switch, Table, TintColor, Tooltip,
Checkbox, ContentGroup, DecoratedIcon, ElevationIndex, Facepile, IconDecoration, Indicator,
Switch, Table, TintColor, ToggleWithLabel, Tooltip,
};
use crate::{Item, Workspace};
@@ -369,12 +369,12 @@ impl ThemePreview {
.overflow_scroll()
.size_full()
.gap_2()
.child(Switch::render_component_previews(cx))
.child(ContentGroup::render_component_previews(cx))
.child(IconDecoration::render_component_previews(cx))
.child(DecoratedIcon::render_component_previews(cx))
.child(Checkbox::render_component_previews(cx))
.child(CheckboxWithLabel::render_component_previews(cx))
.child(Switch::render_component_previews(cx))
.child(ToggleWithLabel::render_component_previews(cx))
.child(Facepile::render_component_previews(cx))
.child(Button::render_component_previews(cx))
.child(Indicator::render_component_previews(cx))

View File

@@ -927,7 +927,7 @@ impl ZetaInlineCompletionProvider {
impl inline_completion::InlineCompletionProvider for ZetaInlineCompletionProvider {
fn name() -> &'static str {
"zeta"
"Zeta"
}
fn is_enabled(