diff --git a/app/gui/view/documentation/src/html.rs b/app/gui/view/documentation/src/html.rs index 4d28ce1de4..802a7c3a14 100644 --- a/app/gui/view/documentation/src/html.rs +++ b/app/gui/view/documentation/src/html.rs @@ -63,16 +63,29 @@ fn svg_icon(content: &'static str) -> impl Render { /// Render entry documentation to HTML code with Tailwind CSS styles. #[profile(Detail)] pub fn render(docs: EntryDocumentation) -> String { - match docs { + let html = match docs { EntryDocumentation::Placeholder(placeholder) => match placeholder { Placeholder::NoDocumentation => String::from("No documentation available."), Placeholder::VirtualComponentGroup { name } => render_virtual_component_group_docs(name), }, EntryDocumentation::Docs(docs) => render_documentation(docs), + }; + match validate_utf8(&html) { + Ok(_) => html, + Err(_) => { + error!("Internal error. Generated HTML is not valid utf-8. This is bug #5813."); + String::from("Failed to load documentation.") + } } } +#[profile(Debug)] +fn validate_utf8(s: &str) -> Result<&str, std::str::Utf8Error> { + let bytes = s.as_bytes(); + std::str::from_utf8(bytes) +} + fn render_documentation(docs: Documentation) -> String { match docs { Documentation::Module(module_docs) => render_module_documentation(&module_docs, None), diff --git a/app/gui/view/documentation/src/lib.rs b/app/gui/view/documentation/src/lib.rs index a1f827815c..1436b07675 100644 --- a/app/gui/view/documentation/src/lib.rs +++ b/app/gui/view/documentation/src/lib.rs @@ -18,21 +18,12 @@ //! [`Tailwind CSS`]: https://tailwindcss.com/ // === Features === -#![feature(associated_type_bounds)] -#![feature(associated_type_defaults)] #![feature(drain_filter)] -#![feature(fn_traits)] #![feature(option_result_contains)] -#![feature(specialization)] -#![feature(trait_alias)] -#![feature(type_alias_impl_trait)] -#![feature(unboxed_closures)] // === Standard Linter Configuration === #![deny(non_ascii_idents)] -#![warn(unsafe_code)] #![allow(clippy::bool_to_int_with_if)] #![allow(clippy::let_and_return)] -#![allow(incomplete_features)] // To be removed, see: https://github.com/enso-org/ide/issues/1559 #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] @@ -64,10 +55,8 @@ use ensogl::Animation; use ensogl_component::shadow; use ensogl_derive_theme::FromTheme; use ensogl_hardcoded_theme::application::component_browser::documentation as theme; -use web::Closure; use web::HtmlElement; use web::JsCast; -use web::MouseEvent; pub mod html; @@ -89,6 +78,7 @@ const MIN_CAPTION_HEIGHT: f32 = 1.0; /// Delay before updating the displayed documentation. const DISPLAY_DELAY_MS: i32 = 0; + // === Style === #[derive(Debug, Clone, Copy, Default, FromTheme)] @@ -108,24 +98,20 @@ pub struct Style { // === Model === // ============= -type CodeCopyClosure = Closure; - /// Model of Native visualization that generates documentation for given Enso code and embeds /// it in a HTML container. #[derive(Clone, CloneRef, Debug)] #[allow(missing_docs)] pub struct Model { - outer_dom: DomSymbol, - caption_dom: DomSymbol, - inner_dom: DomSymbol, + outer_dom: DomSymbol, + caption_dom: DomSymbol, + inner_dom: DomSymbol, /// The purpose of this overlay is stop propagating mouse events under the documentation panel /// to EnsoGL shapes, and pass them to the DOM instead. - overlay: overlay::View, - display_object: display::object::Instance, - code_copy_closures: Rc>>, + overlay: overlay::View, + display_object: display::object::Instance, } - impl Model { /// Constructor. fn new(scene: &Scene) -> Self { @@ -164,9 +150,7 @@ impl Model { scene.dom.layers.node_searcher.manage(&inner_dom); scene.dom.layers.node_searcher.manage(&caption_dom); - let code_copy_closures = default(); - Model { outer_dom, inner_dom, caption_dom, overlay, display_object, code_copy_closures } - .init() + Model { outer_dom, inner_dom, caption_dom, overlay, display_object }.init() } fn init(self) -> Self {