Original commit: d7fabd103b
This commit is contained in:
Maciej Mikołajek 2020-08-21 11:16:54 +02:00 committed by GitHub
parent 7e6bc37bf3
commit cd8be60b78
9 changed files with 809 additions and 30 deletions

View File

@ -54,12 +54,13 @@ tags: [product,ui]
| Shortcut | Action |
| -------- | ------ |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>space<kbd> | Toggle visualization visibility of the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>f<kbd> | Cycle visualizations of the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>space</kbd> | Toggle visualization visibility of the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>f</kbd> | Cycle visualizations of the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>\\</kbd> | Toggle documentation view visibility |
### Debug
| Shortcut | Action |
| -------- | ------ |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>d<kbd> | Send test data to the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>d</kbd> | Send test data to the selected node. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>enter</kbd> | Push a hardcoded breadcrumb without navigating. |
| <kbd>cmd</kbd> / <kbd>ctrl</kbd> + <kbd>shift</kbd> + <kbd>arrow up</kbd> | Pop a breadcrumb without navigating. |

View File

@ -1197,6 +1197,7 @@ dependencies = [
"js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
"logger 0.1.0",
"nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parser 0.1.0",
"serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)",
"span-tree 0.1.0",

View File

@ -15,6 +15,7 @@ ensogl = { version = "0.1.0", path = "../../../ensogl"
ensogl-text = { version = "0.1.0", path = "../../../ensogl/lib/text" }
ensogl-text-msdf-sys = { version = "0.1.0", path = "../../../ensogl/lib/text/msdf-sys" }
enso-shapely = { version = "0.1.0", path = "../../../lib/enso-shapely/impl" }
parser = { version = "0.1.0", path = "../parser" }
span-tree = { version = "0.1.0", path = "../span-tree" }
logger = { version = "0.1.0", path = "../../../lib/logger" }
enso-protocol = { version = "0.1.0", path = "../../../ide/lib/enso-protocol" }

View File

@ -18,10 +18,12 @@ pub mod component;
pub mod builtin;
pub mod data;
use crate::graph_editor::builtin::visualization::native::documentation;
use crate::graph_editor::component::node;
use crate::graph_editor::component::type_coloring::MISSING_TYPE_COLOR;
use crate::graph_editor::component::visualization::MockDataGenerator3D;
use crate::graph_editor::component::visualization;
use crate::graph_editor::component::visualization::MockDataGenerator3D;
use crate::graph_editor::component::visualization::MockDocGenerator;
use enso_frp as frp;
use ensogl::application::Application;
@ -314,6 +316,13 @@ ensogl::def_command_api! { Commands
/// Disable mode in which the pressed node will be edited.
edit_mode_off,
/// Documentation open press event. In case the event will be shortly followed by `release_documentation_view_visibility`, the documentation will be shown permanently. In other case, it will be disabled as soon as the `release_documentation_view_visibility` is emitted.
press_documentation_view_visibility,
/// Documentation open release event. See `press_documentation_view_visibility` to learn more.
release_documentation_view_visibility,
/// Enable nodes multi selection mode. It works like inverse mode for single node selection and like merge mode for multi node selection mode.
enable_node_multi_select,
/// Disable nodes multi selection mode. It works like inverse mode for single node selection and like merge mode for multi node selection mode.
@ -387,6 +396,7 @@ pub struct FrpInputs {
pub set_visualization : frp::Source<(NodeId,Option<visualization::Path>)>,
pub register_visualization : frp::Source<Option<visualization::Definition>>,
pub set_visualization_data : frp::Source<(NodeId,visualization::Data)>,
pub set_documentation_data : frp::Source<visualization::Data>,
hover_node_input : frp::Source<Option<EdgeTarget>>,
hover_node_output : frp::Source<Option<EdgeTarget>>,
@ -425,6 +435,7 @@ impl FrpInputs {
cycle_visualization <- source();
set_visualization <- source();
register_visualization <- source();
set_documentation_data <- source();
hover_node_input <- source();
hover_node_output <- source();
@ -441,9 +452,9 @@ impl FrpInputs {
,unset_edge_source,unset_edge_target
,set_node_position,set_expression_type,set_method_pointer,select_node,remove_node
,set_node_expression,connect_nodes,deselect_all_nodes,cycle_visualization
,set_visualization,register_visualization,some_edge_targets_detached
,some_edge_sources_detached,all_edge_targets_attached,hover_node_input
,all_edge_sources_attached,hover_node_output,press_node_output
,set_visualization,register_visualization,set_documentation_data
,some_edge_targets_detached,some_edge_sources_detached,all_edge_targets_attached
,hover_node_input,all_edge_sources_attached,hover_node_output,press_node_output
,set_detached_edge_sources,all_edges_attached
}
}
@ -543,11 +554,12 @@ generate_frp_outputs! {
connection_added : EdgeId,
connection_removed : EdgeId,
visualization_enabled : NodeId,
visualization_disabled : NodeId,
visualization_enabled : NodeId,
visualization_disabled : NodeId,
visualization_enable_fullscreen : NodeId,
visualization_set_preprocessor : (NodeId,data::EnsoCode),
documentation_visible : bool,
}
@ -1094,15 +1106,16 @@ impl GraphEditorModelWithNetwork {
#[derive(Debug,Clone,CloneRef)]
pub struct GraphEditorModel {
pub logger : Logger,
pub display_object : display::object::Instance,
pub app : Application,
pub breadcrumbs : component::Breadcrumbs,
pub cursor : cursor::Cursor,
pub nodes : Nodes,
pub edges : Edges,
touch_state : TouchState,
frp : FrpInputs,
pub logger : Logger,
pub display_object : display::object::Instance,
pub app : Application,
pub breadcrumbs : component::Breadcrumbs,
pub cursor : cursor::Cursor,
pub nodes : Nodes,
pub edges : Edges,
pub documentation_view : documentation::View,
touch_state : TouchState,
frp : FrpInputs,
}
@ -1115,17 +1128,20 @@ impl GraphEditorModel {
, network : &frp::Network
, focus_manager : &FocusManager
) -> Self {
let scene = app.display.scene();
let logger = Logger::new("GraphEditor");
let display_object = display::object::Instance::new(&logger);
let nodes = Nodes::new(&logger);
// let visualizations = Stage::new(scene.clone_ref(), Logger::new("VisualisationCollection"));
let edges = default();
let frp = FrpInputs::new(network);
let touch_state = TouchState::new(network,&scene.mouse.frp);
let breadcrumbs = component::Breadcrumbs::new(scene,focus_manager);
let app = app.clone_ref();
Self {logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs}.init()//visualizations }
let scene = app.display.scene();
let logger = Logger::new("GraphEditor");
let display_object = display::object::Instance::new(&logger);
let nodes = Nodes::new(&logger);
let documentation_view = documentation::View::new(&scene);
let edges = default();
let frp = FrpInputs::new(network);
let touch_state = TouchState::new(network,&scene.mouse.frp);
let breadcrumbs = component::Breadcrumbs::new(scene,focus_manager);
display_object.add_child(&documentation_view);
display_object.remove_child(&documentation_view);
let app = app.clone_ref();
Self {logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs,
documentation_view}.init()
}
fn init(self) -> Self {
@ -1215,6 +1231,15 @@ impl GraphEditorModel {
}
}
fn set_documentation_visibility(&self, is_visible:bool) {
if is_visible { self.app.remove_child(&self.documentation_view) }
else { self.app.add_child(&self.documentation_view) }
}
fn is_documentation_visible(&self) -> bool {
self.documentation_view.has_parent()
}
/// Warning! This function does not remove connected edges. It needs to be handled by the
/// implementation.
fn remove_node(&self, node_id:impl Into<NodeId>) {
@ -1571,6 +1596,8 @@ impl application::shortcut::DefaultShortcutProvider for GraphEditor {
, Self::self_shortcut(shortcut::Action::press (&[Key::Control,Key::Character(" ".into())],&[]) , "press_visualization_visibility")
, Self::self_shortcut(shortcut::Action::double_press (&[Key::Control,Key::Character(" ".into())],&[]) , "double_press_visualization_visibility")
, Self::self_shortcut(shortcut::Action::release (&[Key::Control,Key::Character(" ".into())],&[]) , "release_visualization_visibility")
, Self::self_shortcut(shortcut::Action::press (&[Key::Control,Key::Character("\\".into())],&[]) , "press_documentation_view_visibility")
, Self::self_shortcut(shortcut::Action::release (&[Key::Control,Key::Character("\\".into())],&[]) , "release_documentation_view_visibility")
, Self::self_shortcut(shortcut::Action::press (&[Key::Meta],&[]) , "toggle_node_multi_select")
, Self::self_shortcut(shortcut::Action::release (&[Key::Meta],&[]) , "toggle_node_multi_select")
, Self::self_shortcut(shortcut::Action::press (&[Key::Control],&[]) , "toggle_node_multi_select")
@ -2284,6 +2311,12 @@ fn new_graph_editor(app:&Application) -> GraphEditor {
let data = visualization::Data::from(content);
inputs.set_visualization_data.emit((*node_id,data));
}
let mock_documentaion = MockDocGenerator::default();
let data = mock_documentaion.generate_data();
let content = serde_json::to_value(data).unwrap_or_default();
let data = visualization::Data::from(content);
inputs.set_documentation_data.emit(data);
}));
def _set_data = inputs.set_visualization_data.map(f!([nodes]((node_id,data)) {
@ -2413,6 +2446,31 @@ fn new_graph_editor(app:&Application) -> GraphEditor {
}
// === Documentation Set ===
frp::extend! { network
eval inputs.set_documentation_data ((data) model.documentation_view.frp.send_data.emit(data));
// === Documentation toggle ===
let documentation_press_ev = inputs.press_documentation_view_visibility.clone_ref();
let documentation_release = inputs.release_documentation_view_visibility.clone_ref();
documentation_pressed <- bool(&documentation_release,&documentation_press_ev);
documentation_was_pressed <- documentation_pressed.previous();
documentation_press <- documentation_press_ev.gate_not(&documentation_was_pressed);
documentation_press_on_off <- documentation_press.map(f_!(model.is_documentation_visible()));
outputs.documentation_visible <+ documentation_press_on_off;
// === OUTPUTS REBIND ===
eval outputs.documentation_visible ((vis) model.set_documentation_visibility(*vis));
}
// === Remove Edge ===
frp::extend! { network

View File

@ -1,7 +1,9 @@
//! Examples of defining visualization in Rust using web_sys or ensogl.
pub mod bubble_chart;
pub mod documentation;
pub mod raw_text;
pub use bubble_chart::*;
pub use documentation::*;
pub use raw_text::*;

View File

@ -0,0 +1,256 @@
//! Documentation view visualization generating and presenting Enso Documentation under
//! the documented node.
use crate::prelude::*;
use crate::graph_editor::component::visualization;
use ast::prelude::FallibleResult;
use enso_frp as frp;
use ensogl::display;
use ensogl::display::DomSymbol;
use ensogl::display::scene::Scene;
use ensogl::system::web;
use ensogl::system::web::StyleSetter;
// =================
// === Constants ===
// =================
pub const VIEW_WIDTH : f32 = 300.0;
pub const VIEW_MARGIN : f32 = 15.0;
/// Content in the documentation view when there is no data available.
const PLACEHOLDER_STR : &str = "<h3>Documentation Viewer</h3><p>No documentation available</p>";
const CORNER_RADIUS : f32 = crate::graph_editor::component::node::CORNER_RADIUS;
/// Get documentation view stylesheet from a CSS file.
///
/// TODO [MM] : This file is generated currently from SASS file, and generated code should never
/// be included in a codebase, so it will be moved to rust-based generator to achieve
/// compatibility with IDE's theme manager.
/// Expect them to land with https://github.com/enso-org/ide/issues/709
fn documentation_style() -> String {
format!("<style>{}</style>", include_str!("documentation/style.css"))
}
// =================
// === ViewModel ===
// =================
/// 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 ViewModel {
logger : Logger,
dom : DomSymbol,
size : Rc<Cell<Vector2>>,
}
impl ViewModel {
/// Constructor.
fn new(scene:&Scene) -> Self {
let logger = Logger::new("DocumentationView");
let div = web::create_div();
let dom = DomSymbol::new(&div);
let screen = scene.camera().screen();
let view_height = screen.height - (VIEW_MARGIN * 2.0);
let size_vec = Vector2(VIEW_WIDTH, view_height);
let size = Rc::new(Cell::new(size_vec));
dom.dom().set_style_or_warn("white-space" ,"normal" ,&logger);
dom.dom().set_style_or_warn("overflow-y" ,"auto" ,&logger);
dom.dom().set_style_or_warn("overflow-x" ,"auto" ,&logger);
dom.dom().set_style_or_warn("background-color","rgba(255, 255, 255, 0.85)" ,&logger);
dom.dom().set_style_or_warn("padding" ,"5px" ,&logger);
dom.dom().set_style_or_warn("pointer-events" ,"auto" ,&logger);
dom.dom().set_style_or_warn("border-radius" ,format!("{}px",CORNER_RADIUS),&logger);
dom.dom().set_style_or_warn("width" ,format!("{}px",VIEW_WIDTH) ,&logger);
dom.dom().set_style_or_warn("height" ,format!("{}px",view_height) ,&logger);
scene.dom.layers.main.manage(&dom);
ViewModel {logger,dom,size}.init()
}
fn init(self) -> Self {
self.reload_style();
self
}
/// Set size of the documentation view.
fn set_size(&self, size:Vector2) {
self.size.set(size);
self.reload_style();
}
/// Generate HTML documentation from documented Enso code.
fn gen_html_from(program:String) -> FallibleResult<String> {
let parser = parser::DocParser::new()?;
let output = parser.generate_html_docs(program);
Ok(output?)
}
/// Prepare data string for Doc Parser to work with after deserialization.
/// FIXME [MM]: Removes characters that are not supported by Doc Parser yet.
/// https://github.com/enso-org/enso/issues/1063
fn prepare_data_string(data_inner:&visualization::Json) -> String {
let data_str = serde_json::to_string_pretty(&**data_inner);
let data_str = data_str.unwrap_or_else(|e| format!("<Cannot render data: {}>",e));
let data_str = data_str.replace("\\n", "\n");
data_str.replace("\"", "")
}
/// Create a container for generated content and embed it with stylesheet.
fn push_to_dom(&self, content:String) {
let data_str = format!(r#"<div class="docVis">{}{}</div>"#,documentation_style(),content);
self.dom.dom().set_inner_html(&data_str)
}
/// Receive data, process and present it in the documentation view.
fn receive_data(&self, data:&visualization::Data) -> Result<(),visualization::DataError> {
let data_inner = match data {
visualization::Data::Json {content} => content,
_ => todo!(),
};
let data_str = ViewModel::prepare_data_string(data_inner);
let output = ViewModel::gen_html_from(data_str);
let mut output = output.unwrap_or_else(|_| String::from(PLACEHOLDER_STR));
if output == "" { output = String::from(PLACEHOLDER_STR) }
// FIXME [MM] : Because of how Doc Parser was implemented in Engine repo, there is need to
// remove stylesheet link from generated code, that would otherwise point to
// non-existing file, as now stylesheet is connected by include_str! macro, and
// soon will be replaced by a style generator.
// This hack will be removed when https://github.com/enso-org/enso/issues/1063
// will land in Engine's repo, also fixing non-existent character bug.
let import_css = r#"<link rel="stylesheet" href="style.css" />"#;
let output = output.replace(import_css, "");
self.push_to_dom(output);
Ok(())
}
/// Load an HTML file into the documentation view when user is waiting for data to be received.
/// TODO [MM] : This should be replaced with a EnsoGL spinner in the next PR.
fn load_waiting_screen(&self) {
let spinner = r#"
<div>
<style>
.spinner {
margin: 40vh auto;
width: 70px;
text-align: center;
}
.spinner > div {
width: 18px;
height: 18px;
background-color: rgb(50, 48, 47);
border-radius: 100%;
display: inline-block;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
.spinner .bounce1 {
animation-delay: -0.32s;
}
.spinner .bounce2 {
animation-delay: -0.16s;
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
transform: scale(0);
} 40% {
transform: scale(1.0);
}
}
</style>
<div class="spinner">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
"#;
self.push_to_dom(String::from(spinner))
}
fn reload_style(&self) {
self.dom.set_size(self.size.get());
}
}
// ============
// === View ===
// ============
/// View of the visualization that renders the given documentation as a HTML page.
#[derive(Clone,CloneRef,Debug,Shrinkwrap)]
#[allow(missing_docs)]
pub struct View {
#[shrinkwrap(main_field)]
pub model : ViewModel,
pub frp : visualization::instance::Frp,
network : frp::Network,
}
impl View {
/// Definition of this visualization.
pub fn definition() -> visualization::Definition {
let path = visualization::Path::builtin("Documentation View");
visualization::Definition::new(
visualization::Signature::new_for_any_type(path,visualization::Format::Json),
|scene| { Ok(Self::new(scene).into()) }
)
}
/// Constructor.
pub fn new(scene:&Scene) -> Self {
let network = default();
let frp = visualization::instance::Frp::new(&network);
let model = ViewModel::new(scene);
model.load_waiting_screen();
Self {model,frp,network} . init(scene)
}
fn init(self, scene:&Scene) -> Self {
let network = &self.network;
let model = &self.model;
let frp = &self.frp;
frp::extend! { network
eval frp.set_size ((size) model.set_size(*size));
eval frp.send_data ([frp, model](data) {
if let Err(e) = model.receive_data(data) {
frp.data_receive_error.emit(Some(e));
}
});
eval scene.frp.shape([model,frp](shape) {
model.dom.set_position_x((shape.width - VIEW_WIDTH) / 2.0 - VIEW_MARGIN);
frp.set_size.emit(Vector2::new(VIEW_WIDTH,shape.height - (VIEW_MARGIN * 2.0)));
});
}
self
}
}
impl From<View> for visualization::Instance {
fn from(t: View) -> Self {
Self::new(&t,&t.frp,&t.network)
}
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance {
&self.dom.display_object()
}
}

View File

@ -0,0 +1,431 @@
/*
* TODO [MM] : This file is undergoing drastic changes.
* Expect them to land with https://github.com/enso-org/ide/issues/709
* This file is currently generated from SASS file, and it is very
* temporary. It will be moved to rust - it will become css generator
* connected with the Theme manager to enable dark mode for documentation.
*/
.docVis {
-webkit-font-smoothing: antialiased;
font-style: normal;
word-wrap: break-word;
font-size: 17px;
line-height: 1.52947;
font-weight: 400;
letter-spacing: -0.021em;
font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
color: #333333;
margin: 0;
padding: 0;
}
.docVis p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0;
margin-inline-end: 0;
}
.docVis a:hover {
color: #0070c9 !important;
text-decoration: inherit;
}
.docVis a {
color: #333333;
background-color: transparent;
text-decoration: inherit;
display: inline-block;
transition: all 0.3s ease;
}
.docVis img {
display: block;
}
.docVis code {
color: #0070c9;
background-color: transparent;
font-size: inherit;
font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
line-height: inherit;
display: inline-block;
white-space: pre-wrap;
}
.docVis button {
display: inline-block;
padding: 8px 30px;
margin: 10px 0;
outline: none;
background-color: transparent;
border: 1px solid #333333;
color: #333333;
border-radius: 5px;
font-size: 13px;
vertical-align: top;
transition: all 0.3s ease;
}
.docVis button:hover {
background-color: #333333;
color: #e5e5e5;
}
.docVis b {
font-weight: 600;
}
.docVis h1 {
font-size: 34px;
line-height: 1.08824;
font-weight: 500;
letter-spacing: 0.01em;
}
.docVis h2 {
font-size: 28px;
line-height: 1.1073;
font-weight: 500;
letter-spacing: 0.012em;
}
.Body h2 {
margin: 0.65rem 0 0;
}
.docVis li {
padding-left: 10px;
}
.creator .Unclosed,
.creator .invalidIndent,
.creator .invalidLink {
display: inline;
color: orangered;
}
.creator .Tags .UNRECOGNIZED {
border: 2px solid;
color: orangered;
}
.Unclosed,
.invalidIndent,
.invalidLink {
display: inline;
}
.Header {
font-size: 19px;
font-weight: 500;
}
.Important .Header,
.Info .Header,
.Example .Header {
margin-bottom: 0.7em;
font-weight: 600;
letter-spacing: -0.021em;
line-height: 17px;
font-synthesis: none;
font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
}
.Tags {
margin-left: auto;
margin-right: auto;
margin-bottom: 20px;
padding-top: 15px;
}
.Tags .DEPRECATED,
.Tags .MODIFIED,
.Tags .ADDED,
.Tags .UPCOMING,
.Tags .REMOVED,
.Tags .UNRECOGNIZED {
line-height: 1.5;
font-weight: 400;
border-radius: 4px;
font-size: 12px;
letter-spacing: -0.021em;
display: inline-flex;
padding: 5px 15px;
margin: 2px;
white-space: nowrap;
background: transparent;
}
.Tags .DEPRECATED {
border: 1px solid #d20606;
color: #d20606;
}
.Tags .MODIFIED {
border: 1px solid #003ec3;
color: #003ec3;
}
.Tags .ADDED {
border: 1px solid #79A129;
color: #79A129;
}
.Tags .UPCOMING,
.Tags .REMOVED,
.Tags .UNRECOGNIZED {
border: 1px solid #666666;
color: #666666;
}
.ExtForTagDetails {
margin: 0 3px;
color: #999999;
}
.Raw,
.Important,
.Info,
.CodeBlock,
.Example {
margin-top: 0;
margin-left: auto;
margin-right: auto;
position: relative;
text-decoration: inherit;
}
.Body .Raw {
margin-bottom: 0.6rem;
font-size: 17px;
line-height: 1.52947;
font-weight: 400;
letter-spacing: -0.021em;
font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
color: #333333;
font-style: normal;
}
.Important,
.Info,
.CodeBlock,
.Example {
font-size: 17px;
padding: 15px 10px 15px 20px;
border: 0;
border-radius: 6px;
margin: 0.7em 0;
}
.Important {
background-color: #FBECC2;
}
.Info {
background-color: #D6E1CA;
}
.Example {
background-color: #fafafa;
}
.CodeBlock {
background-color: #fefefe;
margin: 10px 20px;
display: none;
}
.CodeBlock code {
font-family: monospace;
}
.Def {
margin: 40px auto auto;
padding: 0 15px;
text-decoration: inherit;
}
.Def .Synopsis,
.Def .Body,
.Def .Tags,
.Def .ASTData {
padding-left: 0;
text-decoration: inherit;
}
.Def .Synopsis {
padding: 0;
margin-bottom: 15px;
font-size: 17px;
font-weight: 400;
color: #333333;
font-style: normal;
}
.Def .constr {
padding: 25px 0;
margin: 0;
}
.Def .DefDoc .Body {
display: none;
}
.Def .DefDoc .documentation {
display: inline-flex;
width: 100%;
margin-bottom: 10px;
}
.Def .DefDoc .documentation .ASTHead {
width: 30% !important;
margin: 10px 0;
}
.Def .DefDoc .documentation .ASTHead .DefTitle,
.Def .DefDoc .documentation .ASTHead .Infix {
padding: 0;
font-size: 17px;
font-weight: 400;
font-style: normal;
text-decoration: inherit;
}
.Def .DefDoc .documentation .ASTData {
width: 70% !important;
}
.Def .DefDoc .documentation .Doc {
text-decoration: inherit;
}
.Def .DefDoc .documentation .Doc .Synopsis {
text-decoration: inherit;
margin: 10px 0;
}
.Def .DefDoc .documentation .Tags {
margin: 2px 0 0 auto;
padding: 0;
}
.Def .DefNoDoc {
padding-bottom: 10px;
}
.DefTitle {
display: inline-flex;
font-size: x-large;
font-weight: 400;
margin-bottom: 20px;
}
.DefArgs {
margin-left: 5px;
font-weight: 400;
color: #0070c9;
}
.Synopsis,
.Body {
margin: 0 auto;
padding: 5px;
text-align: left;
}
.Synopsis {
margin-top: 35px;
font-size: 20px;
}
.Documentation .ASTData,
.Documentation .ASTHead {
text-align: left;
line-height: 1.05;
border-radius: 6px;
}
.Documentation .ASTData {
width: 100%;
background-color: #fafafa;
}
.Documentation .ASTHead {
margin: 20px auto 5px;
/*background-color: #fafafa;*/
}
.Documentation .ASTHead .DefTitle {
font-size: 42px;
margin: 0;
}
.Documentation .ASTData .ASTHead {
/*background-color: #fafafa;*/
}
.Documentation .ASTData .ASTHead .DefTitle {
font-size: x-large;
}
.Documentation .Documented {
margin: 0;
width: 100%;
background-color: #ffffff;
}
.Documentation .DefNoBody {
text-decoration: inherit;
}
@media (max-width: 500px) {
.Synopsis,
.Body,
.Tags,
.Documentation .ASTData .Def {
max-width: 380px;
}
.Documentation .ASTHead,
.DefNoBody,
.DefBody {
max-width: 400px;
}
.Def {
padding: 5px;
}
}
@media (min-width: 500px) {
.Synopsis,
.Body,
.Tags,
.Documentation .ASTData .Def {
max-width: 440px;
}
.Documentation .ASTHead,
.DefNoBody,
.DefBody {
max-width: 470px;
}
}
@media (min-width: 600px) {
.Synopsis,
.Body,
.Tags,
.Documentation .ASTData .Def {
max-width: 490px;
}
.Documentation .ASTHead,
.DefNoBody,
.DefBody {
max-width: 520px;
}
}
@media (min-width: 900px) {
.Synopsis,
.Body,
.Tags,
.Documentation .ASTData .Def {
max-width: 680px;
}
.Documentation .ASTHead,
.DefNoBody,
.DefBody {
max-width: 710px;
}
}
@media (min-width: 1300px) {
.Synopsis,
.Body,
.Tags,
.Documentation .ASTData .Def {
max-width: 790px;
}
.Documentation .ASTHead,
.DefNoBody,
.DefBody {
max-width: 820px;
}
}

View File

@ -145,3 +145,32 @@ impl MockDataGenerator3D {
]
}
}
/// The `MockDocGenerator` creates sample documentation string in the format of `String`.
#[derive(Clone,CloneRef,Copy,Debug,Default)]
pub struct MockDocGenerator;
impl MockDocGenerator {
/// Generate new data set.
pub fn generate_data(self) -> String {
let input = r#"
##
Optional values.
Type `Option` represents an optional value: every `Option` is either `Some`
and contains a value, or `None`, and does not.
? Information
`Option`s are commonly paired with pattern matching to query the presence of
a value and take action, always accounting for the None case.
type Option a
## The `Some` type indicates a presence of a value.
type Some a
## The `None` type indicates a lack of a value.
type None
"#;
input.to_string()
}
}

View File

@ -35,7 +35,7 @@ impl Path {
/// Constructor.
pub fn new(library:impl Into<data::LibraryName>, name:impl Into<Name>) -> Self {
let library = library.into();
let name = name.into();
let name = name.into();
Self {library,name}
}