diff --git a/compiler/builtins/docs/Str.roc b/compiler/builtins/docs/Str.roc index 5313cac60b..4789db17b2 100644 --- a/compiler/builtins/docs/Str.roc +++ b/compiler/builtins/docs/Str.roc @@ -1,8 +1,42 @@ interface Str - exposes [ Str, decimal, split, isEmpty, startsWith, endsWith, contains, anyGraphemes, allGraphemes, join, joinWith, padGraphemesStart, padGraphemesEnd, graphemes, reverseGraphemes, isCaseInsensitiveEq, isCaseInsensitiveNeq, walkGraphemes, isCapitalized, isAllUppercase, isAllLowercase, toUtf8, toUtf16, toUtf32, trim, walkUtf8, walkUtf16, walkUtf32, walkRevUtf8, walkRevUtf16, walkRevUtf32 ] + exposes + [ + Str, + decimal, + split, + isEmpty, + startsWith, + endsWith, + contains, + anyGraphemes, + allGraphemes, + join, + joinWith, + padGraphemesStart, + padGraphemesEnd, + graphemes, + reverseGraphemes, + isCaseInsensitiveEq, + isCaseInsensitiveNeq, + walkGraphemes, + isCapitalized, + isAllUppercase, + isAllLowercase, + toUtf8, + toUtf16, + toUtf32, + trim, + walkUtf8, + walkUtf16, + walkUtf32, + walkRevUtf8, + walkRevUtf16, + walkRevUtf32 + ] imports [] -## # Types +## # Types +## ## Dealing with text is a deep topic, so by design, Roc's `Str` module sticks ## to the basics. ## diff --git a/compiler/load/src/docs.rs b/compiler/load/src/docs.rs index 52ea66a45d..ae46aabdf3 100644 --- a/compiler/load/src/docs.rs +++ b/compiler/load/src/docs.rs @@ -1,9 +1,11 @@ +use crate::docs::DocEntry::DetatchedDoc; use crate::docs::TypeAnnotation::{Apply, BoundVariable, Record, TagUnion}; use inlinable_string::InlinableString; use roc_module::ident::ModuleName; use roc_module::symbol::IdentIds; use roc_parse::ast; -use roc_parse::ast::AssignedField; +use roc_parse::ast::CommentOrNewline; +use roc_parse::ast::{AssignedField, Def}; use roc_region::all::Located; // Documentation generation requirements @@ -19,12 +21,17 @@ pub struct Documentation { #[derive(Debug, Clone)] pub struct ModuleDocumentation { pub name: String, - pub docs: String, pub entries: Vec, } #[derive(Debug, Clone)] -pub struct DocEntry { +pub enum DocEntry { + DocDef(DocDef), + DetatchedDoc(String), +} + +#[derive(Debug, Clone)] +pub struct DocDef { pub name: String, pub type_vars: Vec, pub type_annotation: Option, @@ -76,17 +83,40 @@ pub fn generate_module_docs<'a>( parsed_defs .iter() .fold((vec![], None), |(acc, maybe_comments_after), def| { - generate_module_doc(exposed_ident_ids, acc, maybe_comments_after, &def.value) + generate_entry_doc(exposed_ident_ids, acc, maybe_comments_after, &def.value) }); ModuleDocumentation { name: module_name.as_str().to_string(), - docs: "".to_string(), entries, } } -fn generate_module_doc<'a>( +fn detatched_docs_from_comments_and_new_lines<'a>( + comments_or_new_lines: &'a [roc_parse::ast::CommentOrNewline<'a>], +) -> Vec { + let mut detatched_docs: Vec = Vec::new(); + + let mut docs = String::new(); + + for comment_or_new_line in comments_or_new_lines.iter() { + match comment_or_new_line { + CommentOrNewline::DocComment(doc_str) => { + docs.push_str(doc_str); + docs.push('\n'); + } + + CommentOrNewline::LineComment(_) | CommentOrNewline::Newline => { + detatched_docs.push(docs.clone()); + docs = String::new(); + } + } + } + + detatched_docs +} + +fn generate_entry_doc<'a>( exposed_ident_ids: &'a IdentIds, mut acc: Vec, before_comments_or_new_lines: Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>, @@ -95,58 +125,62 @@ fn generate_module_doc<'a>( Vec, Option<&'a [roc_parse::ast::CommentOrNewline<'a>]>, ) { - use roc_parse::ast::Def::*; use roc_parse::ast::Pattern; match def { - SpaceBefore(sub_def, comments_or_new_lines) => { + Def::SpaceBefore(sub_def, comments_or_new_lines) => { // Comments before a definition are attached to the current defition - generate_module_doc(exposed_ident_ids, acc, Some(comments_or_new_lines), sub_def) + + for detatched_doc in detatched_docs_from_comments_and_new_lines(comments_or_new_lines) { + acc.push(DetatchedDoc(detatched_doc)); + } + + generate_entry_doc(exposed_ident_ids, acc, Some(comments_or_new_lines), sub_def) } - SpaceAfter(sub_def, comments_or_new_lines) => { + Def::SpaceAfter(sub_def, comments_or_new_lines) => { let (new_acc, _) = // If there are comments before, attach to this definition - generate_module_doc(exposed_ident_ids, acc, before_comments_or_new_lines, sub_def); + generate_entry_doc(exposed_ident_ids, acc, before_comments_or_new_lines, sub_def); // Comments after a definition are attached to the next definition (new_acc, Some(comments_or_new_lines)) } - Annotation(loc_pattern, _loc_ann) => match loc_pattern.value { + Def::Annotation(loc_pattern, _loc_ann) => match loc_pattern.value { Pattern::Identifier(identifier) => { // Check if the definition is exposed if exposed_ident_ids .get_id(&InlinableString::from(identifier)) .is_some() { - let entry = DocEntry { + let doc_def = DocDef { name: identifier.to_string(), type_annotation: None, type_vars: Vec::new(), docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), }; - acc.push(entry); + acc.push(DocEntry::DocDef(doc_def)); } (acc, None) } _ => (acc, None), }, - AnnotatedBody { ann_pattern, .. } => match ann_pattern.value { + Def::AnnotatedBody { ann_pattern, .. } => match ann_pattern.value { Pattern::Identifier(identifier) => { // Check if the definition is exposed if exposed_ident_ids .get_id(&InlinableString::from(identifier)) .is_some() { - let entry = DocEntry { + let doc_def = DocDef { name: identifier.to_string(), type_annotation: None, type_vars: Vec::new(), docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), }; - acc.push(entry); + acc.push(DocEntry::DocDef(doc_def)); } (acc, None) } @@ -154,7 +188,7 @@ fn generate_module_doc<'a>( _ => (acc, None), }, - Alias { name, vars, ann } => { + Def::Alias { name, vars, ann } => { let mut type_vars = Vec::new(); for var in vars.iter() { @@ -163,22 +197,22 @@ fn generate_module_doc<'a>( } } - let entry = DocEntry { + let doc_def = DocDef { name: name.value.to_string(), type_annotation: type_to_docs(ann.value), type_vars, docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), }; - acc.push(entry); + acc.push(DocEntry::DocDef(doc_def)); (acc, None) } - Body(_, _) => (acc, None), + Def::Body(_, _) => (acc, None), - Expect(c) => todo!("documentation for tests {:?}", c), + Def::Expect(c) => todo!("documentation for tests {:?}", c), - NotYetImplemented(s) => todo!("{}", s), + Def::NotYetImplemented(s) => todo!("{}", s), } } @@ -327,21 +361,20 @@ fn tag_to_doc(tag: ast::Tag) -> Option { fn comments_or_new_lines_to_docs<'a>( comments_or_new_lines: &'a [roc_parse::ast::CommentOrNewline<'a>], ) -> Option { - use roc_parse::ast::CommentOrNewline::*; - let mut docs = String::new(); for comment_or_new_line in comments_or_new_lines.iter() { match comment_or_new_line { - DocComment(doc_str) => { + CommentOrNewline::DocComment(doc_str) => { docs.push_str(doc_str); docs.push('\n'); } - Newline | LineComment(_) => { + CommentOrNewline::Newline | CommentOrNewline::LineComment(_) => { docs = String::new(); } } } + if docs.is_empty() { None } else { diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 367bdb5161..3a86b4b77d 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -3516,7 +3516,6 @@ fn fabricate_effects_module<'a>( // Should a effect module ever have a ModuleDocumentation? let module_docs = ModuleDocumentation { name: String::from(name), - docs: String::from("idk fix this later"), entries: Vec::new(), }; diff --git a/docs/src/lib.rs b/docs/src/lib.rs index 50e63d6b6f..b5ab4347f5 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -1,7 +1,7 @@ extern crate pulldown_cmark; use roc_builtins::std::StdLib; use roc_can::builtins::builtin_defs_map; -use roc_load::docs::TypeAnnotation; +use roc_load::docs::{DocEntry, TypeAnnotation}; use roc_load::docs::{ModuleDocumentation, RecordField}; use roc_load::file::LoadingProblem; @@ -86,41 +86,48 @@ fn render_main_content(module: &ModuleDocumentation) -> String { .as_str(), ); - buf.push_str(markdown_to_html(module.docs.clone()).as_str()); + // buf.push_str(markdown_to_html(module.docs.clone()).as_str()); for entry in &module.entries { - let mut href = String::new(); - href.push('#'); - href.push_str(entry.name.as_str()); + match entry { + DocEntry::DocDef(doc_def) => { + let mut href = String::new(); + href.push('#'); + href.push_str(doc_def.name.as_str()); - let name = entry.name.as_str(); + let name = doc_def.name.as_str(); - let mut content = String::new(); + let mut content = String::new(); - content.push_str(html_node("a", vec![("href", href.as_str())], name).as_str()); + content.push_str(html_node("a", vec![("href", href.as_str())], name).as_str()); - for type_var in &entry.type_vars { - content.push(' '); - content.push_str(type_var.as_str()); - } + for type_var in &doc_def.type_vars { + content.push(' '); + content.push_str(type_var.as_str()); + } - if let Some(type_ann) = &entry.type_annotation { - content.push_str(" : "); - type_annotation_to_html(0, &mut content, &type_ann); - } + if let Some(type_ann) = &doc_def.type_annotation { + content.push_str(" : "); + type_annotation_to_html(0, &mut content, &type_ann); + } - buf.push_str( - html_node( - "h3", - vec![("id", name), ("class", "entry-name")], - content.as_str(), - ) - .as_str(), - ); + buf.push_str( + html_node( + "h3", + vec![("id", name), ("class", "entry-name")], + content.as_str(), + ) + .as_str(), + ); - if let Some(docs) = &entry.docs { - buf.push_str(markdown_to_html(docs.to_string()).as_str()); - } + if let Some(docs) = &doc_def.docs { + buf.push_str(markdown_to_html(docs.to_string()).as_str()); + } + } + DocEntry::DetatchedDoc(docs) => { + buf.push_str(markdown_to_html(docs.to_string()).as_str()); + } + }; } buf @@ -218,20 +225,22 @@ fn render_module_links(modules: &[ModuleDocumentation]) -> String { let mut entries_buf = String::new(); for entry in &module.entries { - let mut entry_href = String::new(); + if let DocEntry::DocDef(doc_def) = entry { + let mut entry_href = String::new(); - entry_href.push_str(href.as_str()); - entry_href.push('#'); - entry_href.push_str(entry.name.as_str()); + entry_href.push_str(href.as_str()); + entry_href.push('#'); + entry_href.push_str(doc_def.name.as_str()); - entries_buf.push_str( - html_node( - "a", - vec![("href", entry_href.as_str())], - entry.name.as_str(), - ) - .as_str(), - ); + entries_buf.push_str( + html_node( + "a", + vec![("href", entry_href.as_str())], + doc_def.name.as_str(), + ) + .as_str(), + ); + } } entries_buf