Files
Ely-GPUI-Components/examples/gallery/pages/editor/panels.rs
T

260 lines
8.6 KiB
Rust

use ely_gpui_component::{
editor::{
ConsoleEntry, DebugConsole, Extension, ExtensionAction, ExtensionState, ExtensionsPanel,
OutputPanel, Problem, ProblemsPanel,
},
forms::TextInput,
primitives::Severity,
typography::Caption,
};
use gpui::{App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use crate::ui::{keep, section, set};
fn problems() -> Vec<Problem> {
let problem = |path: &str, line, column, severity, message: &str, source: &str| Problem {
path: path.to_string().into(),
line,
column,
severity,
message: message.to_string().into(),
source: Some(source.to_string().into()),
};
vec![
problem(
"src/main.rs",
45,
21,
Severity::Danger,
"mismatched types: expected `u32`, found `usize`",
"rustc",
),
problem(
"src/main.rs",
46,
8,
Severity::Warning,
"unused variable: `spare`",
"rustc",
),
problem(
"src/palette.rs",
0,
23,
Severity::Info,
"a BTreeMap keeps a steady order",
"clippy",
),
problem(
"src/theme/tokens.rs",
112,
4,
Severity::Warning,
"this function has too many arguments (8/7)",
"clippy",
),
]
}
pub fn problems_and_output(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let shown = keep(
"panels-shown",
|| vec![Severity::Danger, Severity::Warning, Severity::Info],
window,
cx,
);
let channel = keep("panels-channel", || SharedString::from("Build"), window, cx);
let follow = keep("panels-follow", || true, window, cx);
let cleared = keep("panels-cleared", || false, window, cx);
let opened = keep("panels-problem", || None::<SharedString>, window, cx);
let (now_shown, now_channel, now_follow, now_cleared, said) = (
shown.read(cx).clone(),
channel.read(cx).clone(),
*follow.read(cx),
*cleared.read(cx),
opened.read(cx).clone(),
);
let lines: Vec<&str> = if now_cleared {
Vec::new()
} else if now_channel.as_ref() == "Build" {
vec![
" Compiling ely-gpui-component v0.1.0",
"warning: unused variable: `spare`",
"error[E0308]: mismatched types",
" --> src/main.rs:46:22",
"error: could not compile `palette` due to 1 previous error",
]
} else {
vec![
"[info] rust-analyzer started",
"[debug] indexing 214 files",
"[info] indexed in 1.2 s",
]
};
let (show, pick, keep_up, clear, open) = (
shown.clone(),
channel.clone(),
follow.clone(),
cleared.clone(),
opened.clone(),
);
let reset = cleared.clone();
section(
"ProblemsPanel / DiagnosticsList / OutputPanel",
"Every problem by file, worst first, with toggles by severity; and a tool's log by channel, levels tinted, following the newest line.",
cx,
)
.child(
div()
.flex()
.gap_8()
.child(
div().flex_1().child(
ProblemsPanel::new("panels-problems", problems())
.shown(now_shown)
.on_shown(move |next, _, cx| set(&show, next, cx))
.on_open(move |problem, _, cx| {
set(&open, Some(format!("Opened {}:{}.", problem.path, problem.line + 1).into()), cx)
}),
),
)
.child(
div().w(px(400.)).h(px(220.)).child(
OutputPanel::new("panels-output", ["Build", "Language server"], now_channel, lines)
.follow(now_follow)
.on_channel(move |name, _, cx| {
set(&pick, name.clone(), cx);
set(&reset, false, cx);
})
.on_follow(move |on, _, cx| set(&keep_up, on, cx))
.on_clear(move |_, cx| set(&clear, true, cx)),
),
),
)
.children(said.map(Caption::new))
}
pub fn console_and_extensions(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let field = window.use_keyed_state("panels-console-field", cx, TextInput::new);
let entries = keep(
"panels-console",
|| {
vec![
ConsoleEntry::Input("tints.len()".into()),
ConsoleEntry::Value("5".into(), "usize".into()),
ConsoleEntry::Input("palette.lookup(\"accent\", 0.5).red".into()),
ConsoleEntry::Value("0.605".into(), "f32".into()),
ConsoleEntry::Input("spare + missing".into()),
ConsoleEntry::Error("cannot find value `missing` in this scope".into()),
]
},
window,
cx,
);
let states = keep(
"panels-extensions",
|| {
vec![
ExtensionState::Installed,
ExtensionState::Available,
ExtensionState::Outdated,
ExtensionState::Disabled,
]
},
window,
cx,
);
let now_entries = entries.read(cx).clone();
let now_states = states.read(cx).clone();
let extension = |ix: usize,
id: &str,
name: &str,
publisher: &str,
description: &str,
version: &str,
installs: u64,
rating: f32| Extension {
id: id.to_string().into(),
name: name.to_string().into(),
publisher: publisher.to_string().into(),
description: description.to_string().into(),
version: version.to_string().into(),
installs,
rating,
state: now_states[ix],
};
let extensions = vec![
extension(
0,
"rust",
"Rust",
"Ely Tools",
"Syntax, completions and checks for Rust.",
"1.4.2",
2_410_000,
4.8,
),
extension(
1,
"toml",
"Even Better TOML",
"Tamasfe",
"TOML with schemas and formatting.",
"0.19.2",
830_000,
4.6,
),
extension(
2,
"lens",
"Git Lens",
"Line Labs",
"Who changed each line, and when.",
"14.1.0",
5_900_000,
4.4,
),
extension(
3,
"vim",
"Vim",
"Modal Folk",
"Modal editing with the keys you know.",
"1.27.3",
1_200_000,
4.2,
),
];
let (eval, act) = (entries.clone(), states.clone());
section(
"DebugConsole / ExtensionsPanel / PluginList",
"An expression prompt beside a paused program; and extensions with their reach, rating, and the one action each needs next.",
cx,
)
.child(
div()
.flex()
.gap_8()
.child(
div().w(px(380.)).child(DebugConsole::new("panels-console", &field, now_entries).on_eval(move |text, _, cx| {
let mut next = eval.read(cx).clone();
next.push(ConsoleEntry::Input(text.clone()));
next.push(match text.trim().parse::<i64>() {
Ok(value) => ConsoleEntry::Value(value.to_string().into(), "i64".into()),
Err(_) => ConsoleEntry::Error(format!("cannot find value `{}` in this scope", text.trim()).into()),
});
set(&eval, next, cx)
})),
)
.child(div().flex_1().child(ExtensionsPanel::new("panels-extensions", extensions).on_action(move |id, action, _, cx| {
let ix = ["rust", "toml", "lens", "vim"].iter().position(|known| *known == id.as_ref()).expect("a listed extension");
let mut next = act.read(cx).clone();
next[ix] = match action {
ExtensionAction::Install | ExtensionAction::Enable | ExtensionAction::Update => ExtensionState::Installed,
ExtensionAction::Uninstall => ExtensionState::Available,
};
set(&act, next, cx)
}))),
)
}