mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Merge pull request #5753 from roc-lang/fix-missing-docs-stuff
Fix various missing docs implementations
This commit is contained in:
commit
2eb8326a70
4 changed files with 258 additions and 58 deletions
|
@ -28,7 +28,7 @@ interface Hash
|
|||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, Nat, Dec },
|
||||
]
|
||||
|
||||
## A value that can hashed.
|
||||
## A value that can be hashed.
|
||||
Hash implements
|
||||
## Hashes a value into a [Hasher].
|
||||
## Note that [hash] does not produce a hash value itself; the hasher must be
|
||||
|
|
|
@ -54,11 +54,30 @@ pub enum TypeAnnotation {
|
|||
fields: Vec<RecordField>,
|
||||
extension: Box<TypeAnnotation>,
|
||||
},
|
||||
Tuple {
|
||||
elems: Vec<TypeAnnotation>,
|
||||
extension: Box<TypeAnnotation>,
|
||||
},
|
||||
Ability {
|
||||
members: Vec<AbilityMember>,
|
||||
},
|
||||
Wildcard,
|
||||
NoTypeAnn,
|
||||
Where {
|
||||
ann: Box<TypeAnnotation>,
|
||||
implements: Vec<ImplementsClause>,
|
||||
},
|
||||
As {
|
||||
ann: Box<TypeAnnotation>,
|
||||
name: String,
|
||||
vars: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImplementsClause {
|
||||
pub name: String,
|
||||
pub abilities: Vec<TypeAnnotation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -540,7 +559,57 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
|
|||
}
|
||||
}
|
||||
ast::TypeAnnotation::Wildcard => TypeAnnotation::Wildcard,
|
||||
_ => NoTypeAnn,
|
||||
ast::TypeAnnotation::As(loc_ann, _comments, type_header) => TypeAnnotation::As {
|
||||
ann: Box::new(type_to_docs(in_func_type_ann, loc_ann.value)),
|
||||
name: type_header.name.value.to_string(),
|
||||
vars: type_header
|
||||
.vars
|
||||
.iter()
|
||||
.filter_map(|loc_pattern| match loc_pattern.value {
|
||||
ast::Pattern::Identifier(ident) => Some(ident.to_string()),
|
||||
_ => None,
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
ast::TypeAnnotation::Tuple { elems, ext } => {
|
||||
let mut doc_elems = Vec::new();
|
||||
|
||||
for loc_ann in elems.items {
|
||||
doc_elems.push(type_to_docs(in_func_type_ann, loc_ann.value));
|
||||
}
|
||||
|
||||
let extension = match ext {
|
||||
None => NoTypeAnn,
|
||||
Some(ext_type_ann) => type_to_docs(in_func_type_ann, ext_type_ann.value),
|
||||
};
|
||||
|
||||
TypeAnnotation::Tuple {
|
||||
elems: doc_elems,
|
||||
extension: Box::new(extension),
|
||||
}
|
||||
}
|
||||
ast::TypeAnnotation::Where(loc_ann, implements) => TypeAnnotation::Where {
|
||||
ann: Box::new(type_to_docs(in_func_type_ann, loc_ann.value)),
|
||||
implements: implements
|
||||
.iter()
|
||||
.map(|clause| {
|
||||
let abilities = clause
|
||||
.value
|
||||
.abilities
|
||||
.iter()
|
||||
.map(|ability| type_to_docs(in_func_type_ann, ability.value))
|
||||
.collect();
|
||||
|
||||
ImplementsClause {
|
||||
name: clause.value.var.value.item().to_string(),
|
||||
abilities,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
ast::TypeAnnotation::Malformed(_) | ast::TypeAnnotation::Inferred => {
|
||||
TypeAnnotation::NoTypeAnn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,13 @@ impl<'a, T> Spaced<'a, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn item(&self) -> &T {
|
||||
match self {
|
||||
Spaced::Item(answer) => answer,
|
||||
Spaced::SpaceBefore(next, _spaces) | Spaced::SpaceAfter(next, _spaces) => next.item(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Debug for Spaced<'a, T> {
|
||||
|
|
|
@ -11,6 +11,7 @@ use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threadin
|
|||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_parse::ident::{parse_ident, Accessor, Ident};
|
||||
use roc_parse::keyword;
|
||||
use roc_parse::state::State;
|
||||
use roc_region::all::Region;
|
||||
use std::fs;
|
||||
|
@ -260,7 +261,13 @@ fn render_module_documentation(
|
|||
let type_ann = &doc_def.type_annotation;
|
||||
|
||||
if !matches!(type_ann, TypeAnnotation::NoTypeAnn) {
|
||||
content.push_str(" : ");
|
||||
// Ability declarations don't have ":" after the name, just `implements`
|
||||
if !matches!(type_ann, TypeAnnotation::Ability { .. }) {
|
||||
content.push_str(" :");
|
||||
}
|
||||
|
||||
content.push(' ');
|
||||
|
||||
type_annotation_to_html(0, &mut content, type_ann, false);
|
||||
}
|
||||
|
||||
|
@ -626,6 +633,7 @@ fn type_annotation_to_html(
|
|||
TypeAnnotation::Function { args, output } => {
|
||||
let mut paren_is_open = false;
|
||||
let mut peekable_args = args.iter().peekable();
|
||||
|
||||
while let Some(arg) = peekable_args.next() {
|
||||
if is_multiline {
|
||||
if !should_be_multiline(arg) {
|
||||
|
@ -638,8 +646,7 @@ fn type_annotation_to_html(
|
|||
paren_is_open = true;
|
||||
}
|
||||
|
||||
let child_needs_parens =
|
||||
matches!(arg, TypeAnnotation::Function { args: _, output: _ });
|
||||
let child_needs_parens = matches!(arg, TypeAnnotation::Function { .. });
|
||||
type_annotation_to_html(indent_level, buf, arg, child_needs_parens);
|
||||
|
||||
if peekable_args.peek().is_some() {
|
||||
|
@ -650,9 +657,11 @@ fn type_annotation_to_html(
|
|||
if is_multiline {
|
||||
new_line(buf);
|
||||
indent(buf, indent_level + 1);
|
||||
} else {
|
||||
buf.push(' ');
|
||||
}
|
||||
|
||||
buf.push_str(" -> ");
|
||||
buf.push_str("-> ");
|
||||
|
||||
let mut next_indent_level = indent_level;
|
||||
|
||||
|
@ -665,8 +674,54 @@ fn type_annotation_to_html(
|
|||
buf.push(')');
|
||||
}
|
||||
}
|
||||
TypeAnnotation::Ability { members: _ } => {
|
||||
// TODO(abilities): fill me in
|
||||
TypeAnnotation::Ability { members } => {
|
||||
buf.push_str(keyword::IMPLEMENTS);
|
||||
|
||||
for member in members {
|
||||
new_line(buf);
|
||||
indent(buf, indent_level + 1);
|
||||
|
||||
// TODO use member.docs somehow. This doesn't look good though:
|
||||
// if let Some(docs) = &member.docs {
|
||||
// buf.push_str("## ");
|
||||
// buf.push_str(docs);
|
||||
|
||||
// new_line(buf);
|
||||
// indent(buf, indent_level + 1);
|
||||
// }
|
||||
|
||||
buf.push_str(&member.name);
|
||||
buf.push_str(" : ");
|
||||
|
||||
type_annotation_to_html(indent_level + 1, buf, &member.type_annotation, false);
|
||||
|
||||
if !member.able_variables.is_empty() {
|
||||
new_line(buf);
|
||||
indent(buf, indent_level + 2);
|
||||
buf.push_str(keyword::WHERE);
|
||||
|
||||
for (index, (name, type_anns)) in member.able_variables.iter().enumerate() {
|
||||
if index != 0 {
|
||||
buf.push(',');
|
||||
}
|
||||
|
||||
buf.push(' ');
|
||||
buf.push_str(name);
|
||||
buf.push(' ');
|
||||
buf.push_str(keyword::IMPLEMENTS);
|
||||
|
||||
for (index, ann) in type_anns.iter().enumerate() {
|
||||
if index != 0 {
|
||||
buf.push_str(" &");
|
||||
}
|
||||
|
||||
buf.push(' ');
|
||||
|
||||
type_annotation_to_html(indent_level + 2, buf, ann, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeAnnotation::ObscuredTagUnion => {
|
||||
buf.push_str("[@..]");
|
||||
|
@ -676,77 +731,146 @@ fn type_annotation_to_html(
|
|||
}
|
||||
TypeAnnotation::NoTypeAnn => {}
|
||||
TypeAnnotation::Wildcard => buf.push('*'),
|
||||
TypeAnnotation::Tuple { elems, extension } => {
|
||||
let elems_len = elems.len();
|
||||
let tuple_indent = indent_level + 1;
|
||||
|
||||
if is_multiline {
|
||||
new_line(buf);
|
||||
indent(buf, tuple_indent);
|
||||
}
|
||||
|
||||
buf.push('(');
|
||||
|
||||
if is_multiline {
|
||||
new_line(buf);
|
||||
}
|
||||
|
||||
let next_indent_level = tuple_indent + 1;
|
||||
|
||||
for (index, elem) in elems.iter().enumerate() {
|
||||
if is_multiline {
|
||||
indent(buf, next_indent_level);
|
||||
}
|
||||
|
||||
type_annotation_to_html(next_indent_level, buf, elem, false);
|
||||
|
||||
if is_multiline {
|
||||
if index < (elems_len - 1) {
|
||||
buf.push(',');
|
||||
}
|
||||
|
||||
new_line(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if is_multiline {
|
||||
indent(buf, tuple_indent);
|
||||
}
|
||||
|
||||
buf.push(')');
|
||||
|
||||
type_annotation_to_html(indent_level, buf, extension, true);
|
||||
}
|
||||
TypeAnnotation::Where { ann, implements } => {
|
||||
type_annotation_to_html(indent_level, buf, ann, false);
|
||||
|
||||
new_line(buf);
|
||||
indent(buf, indent_level + 1);
|
||||
|
||||
buf.push_str(keyword::WHERE);
|
||||
|
||||
let multiline_implements = implements
|
||||
.iter()
|
||||
.any(|imp| imp.abilities.iter().any(should_be_multiline));
|
||||
|
||||
for (index, imp) in implements.iter().enumerate() {
|
||||
if index != 0 {
|
||||
buf.push(',');
|
||||
}
|
||||
|
||||
if multiline_implements {
|
||||
new_line(buf);
|
||||
indent(buf, indent_level + 2);
|
||||
} else {
|
||||
buf.push(' ')
|
||||
}
|
||||
|
||||
buf.push_str(&imp.name);
|
||||
buf.push(' ');
|
||||
buf.push_str(keyword::IMPLEMENTS);
|
||||
buf.push(' ');
|
||||
|
||||
for (index, ability) in imp.abilities.iter().enumerate() {
|
||||
if index != 0 {
|
||||
buf.push_str(" & ");
|
||||
}
|
||||
|
||||
type_annotation_to_html(indent_level, buf, ability, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeAnnotation::As { ann, name, vars } => {
|
||||
type_annotation_to_html(indent_level, buf, ann, true);
|
||||
buf.push(' ');
|
||||
buf.push_str(name);
|
||||
|
||||
for var in vars {
|
||||
buf.push(' ');
|
||||
buf.push_str(var);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn should_be_multiline(type_ann: &TypeAnnotation) -> bool {
|
||||
match type_ann {
|
||||
TypeAnnotation::TagUnion { tags, extension } => {
|
||||
let mut is_multiline = should_be_multiline(extension) || tags.len() > 1;
|
||||
|
||||
for tag in tags {
|
||||
for value in &tag.values {
|
||||
if is_multiline {
|
||||
break;
|
||||
}
|
||||
is_multiline = should_be_multiline(value);
|
||||
}
|
||||
}
|
||||
|
||||
is_multiline
|
||||
tags.len() > 1
|
||||
|| should_be_multiline(extension)
|
||||
|| tags
|
||||
.iter()
|
||||
.any(|tag| tag.values.iter().any(should_be_multiline))
|
||||
}
|
||||
TypeAnnotation::Function { args, output } => {
|
||||
let mut is_multiline = should_be_multiline(output) || args.len() > 2;
|
||||
|
||||
for arg in args {
|
||||
if is_multiline {
|
||||
break;
|
||||
}
|
||||
|
||||
is_multiline = should_be_multiline(arg);
|
||||
}
|
||||
|
||||
is_multiline
|
||||
args.len() > 2 || should_be_multiline(output) || args.iter().any(should_be_multiline)
|
||||
}
|
||||
TypeAnnotation::ObscuredTagUnion => false,
|
||||
TypeAnnotation::ObscuredRecord => false,
|
||||
TypeAnnotation::BoundVariable(_) => false,
|
||||
TypeAnnotation::Apply { parts, .. } => {
|
||||
let mut is_multiline = false;
|
||||
|
||||
for part in parts {
|
||||
is_multiline = should_be_multiline(part);
|
||||
|
||||
if is_multiline {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
is_multiline
|
||||
}
|
||||
TypeAnnotation::Apply { parts, .. } => parts.iter().any(should_be_multiline),
|
||||
TypeAnnotation::Record { fields, extension } => {
|
||||
let mut is_multiline = should_be_multiline(extension) || fields.len() > 1;
|
||||
|
||||
for field in fields {
|
||||
if is_multiline {
|
||||
break;
|
||||
}
|
||||
match field {
|
||||
fields.len() > 1
|
||||
|| should_be_multiline(extension)
|
||||
|| fields.iter().any(|field| match field {
|
||||
RecordField::RecordField {
|
||||
type_annotation, ..
|
||||
} => is_multiline = should_be_multiline(type_annotation),
|
||||
} => should_be_multiline(type_annotation),
|
||||
RecordField::OptionalField {
|
||||
type_annotation, ..
|
||||
} => is_multiline = should_be_multiline(type_annotation),
|
||||
RecordField::LabelOnly { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
is_multiline
|
||||
} => should_be_multiline(type_annotation),
|
||||
RecordField::LabelOnly { .. } => false,
|
||||
})
|
||||
}
|
||||
TypeAnnotation::Ability { .. } => true,
|
||||
TypeAnnotation::Wildcard => false,
|
||||
TypeAnnotation::NoTypeAnn => false,
|
||||
TypeAnnotation::Tuple { elems, extension } => {
|
||||
elems.len() > 1
|
||||
|| should_be_multiline(extension)
|
||||
|| elems.iter().any(should_be_multiline)
|
||||
}
|
||||
TypeAnnotation::Where { ann, implements } => {
|
||||
should_be_multiline(ann)
|
||||
|| implements
|
||||
.iter()
|
||||
.any(|imp| imp.abilities.iter().any(should_be_multiline))
|
||||
}
|
||||
TypeAnnotation::As {
|
||||
ann,
|
||||
name: _,
|
||||
vars: _,
|
||||
} => should_be_multiline(ann),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue