summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2019-12-21 12:13:21 +0100
committerMinijackson <minijackson@riseup.net>2019-12-21 12:13:21 +0100
commite773caea8010b87726ea524d31798fb2e43e12f4 (patch)
tree9034295831afb25f4bfea5a05d9f83d03e69e86c
parentde896baff7e97fac4dde79078c9a2fa1c652576b (diff)
downloadposeidoc-e773caea8010b87726ea524d31798fb2e43e12f4.tar.gz
poseidoc-e773caea8010b87726ea524d31798fb2e43e12f4.zip
newtype in types, more generator config, parsing -> parser
-rw-r--r--src/cli.rs7
-rw-r--r--src/config.rs6
-rw-r--r--src/generator/config.rs52
-rw-r--r--src/generator/mod.rs42
-rw-r--r--src/generator/pandoc.rs19
-rw-r--r--src/main.rs9
-rw-r--r--src/parser/clang/config.rs (renamed from src/parsing/clang/config.rs)8
-rw-r--r--src/parser/clang/entities.rs (renamed from src/parsing/clang/entities.rs)129
-rw-r--r--src/parser/clang/mod.rs (renamed from src/parsing/clang/mod.rs)0
-rw-r--r--src/parser/clang/parsing.rs (renamed from src/parsing/clang/parsing.rs)34
-rw-r--r--src/parser/mod.rs (renamed from src/parsing/mod.rs)0
-rw-r--r--src/types.rs70
12 files changed, 256 insertions, 120 deletions
diff --git a/src/cli.rs b/src/cli.rs
index ff25792..0000644 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -21,11 +21,14 @@ pub(crate) struct Cli {
21 21
22#[derive(Debug, Clone, StructOpt)] 22#[derive(Debug, Clone, StructOpt)]
23pub(crate) enum Command { 23pub(crate) enum Command {
24 Generate { file: String }, 24 Generate {
25 file: String,
26 },
27 Inspect,
25 Config { 28 Config {
26 #[structopt(subcommand)] 29 #[structopt(subcommand)]
27 command: ConfigCommand, 30 command: ConfigCommand,
28 } 31 },
29} 32}
30 33
31#[derive(Debug, Clone, StructOpt)] 34#[derive(Debug, Clone, StructOpt)]
diff --git a/src/config.rs b/src/config.rs
index 72a9ff6..942dfcf 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -2,7 +2,7 @@ use crate::cli::Cli;
2use crate::generator::config::{ 2use crate::generator::config::{
3 Config as GeneratorConfig, ProvidedConfig as ProvidedGeneratorConfig, 3 Config as GeneratorConfig, ProvidedConfig as ProvidedGeneratorConfig,
4}; 4};
5use crate::parsing::clang::config::{Config as ClangConfig, ProvidedConfig as ProvidedClangConfig}; 5use crate::parser::clang::config::{Config as ClangConfig, ProvidedConfig as ProvidedClangConfig};
6 6
7use anyhow::{anyhow, Context, Result}; 7use anyhow::{anyhow, Context, Result};
8use codemap::CodeMap; 8use codemap::CodeMap;
@@ -19,8 +19,8 @@ pub(super) const DEFAULT_PROJECT_CONFIGURATION_FILE_NAME: &str = "poseidoc.toml"
19#[derive(Debug, Clone, Serialize)] 19#[derive(Debug, Clone, Serialize)]
20pub(crate) struct Config { 20pub(crate) struct Config {
21 pub(crate) name: String, 21 pub(crate) name: String,
22 pub(crate) clang: ClangConfig,
23 pub(crate) generator: GeneratorConfig, 22 pub(crate) generator: GeneratorConfig,
23 pub(crate) clang: ClangConfig,
24} 24}
25 25
26impl Default for Config { 26impl Default for Config {
@@ -57,7 +57,7 @@ pub(crate) struct ProvidedConfig {
57 #[structopt(flatten)] 57 #[structopt(flatten)]
58 #[serde(default)] 58 #[serde(default)]
59 pub(crate) clang: ProvidedClangConfig, 59 pub(crate) clang: ProvidedClangConfig,
60 #[structopt(skip)] 60 #[structopt(flatten)]
61 #[serde(default)] 61 #[serde(default)]
62 pub(crate) generator: ProvidedGeneratorConfig, 62 pub(crate) generator: ProvidedGeneratorConfig,
63} 63}
diff --git a/src/generator/config.rs b/src/generator/config.rs
index 43fee60..3057fee 100644
--- a/src/generator/config.rs
+++ b/src/generator/config.rs
@@ -1,40 +1,58 @@
1use crate::types::*;
2
1use serde_derive::{Deserialize, Serialize}; 3use serde_derive::{Deserialize, Serialize};
2use structopt::StructOpt; 4use structopt::StructOpt;
3 5
4use std::collections::{HashMap, HashSet}; 6use std::collections::{HashMap, HashSet};
5 7
8pub(crate) type Inlines = HashMap<Language, HashMap<EntityKind, HashSet<ChildrenKind>>>;
9
6#[derive(Debug, Clone, Serialize)] 10#[derive(Debug, Clone, Serialize)]
7pub(crate) struct Config { 11pub(crate) struct Config {
12 pub(super) from: String,
13 pub(super) to: String,
14 pub(super) pandoc_filters: Vec<String>,
8 /// Tells us in which language, which entity types should inline which children entity type in 15 /// Tells us in which language, which entity types should inline which children entity type in
9 /// their documentation. 16 /// their documentation.
10 /// 17 ///
11 /// e.g. in C++, classes should inline their children methods documentation. 18 /// e.g. in C++, classes should inline their children methods documentation.
12 pub(crate) inlines: HashMap<String, HashMap<String, HashSet<String>>>, 19 pub(super) inlines: Inlines,
13} 20}
14 21
15impl Config { 22impl Config {
16 pub(crate) fn from_merge(_cli: ProvidedConfig, conf: ProvidedConfig) -> Self { 23 pub(crate) fn from_merge(mut cli: ProvidedConfig, mut conf: ProvidedConfig) -> Self {
24 conf.pandoc_filters.append(&mut cli.pandoc_filters);
17 Self { 25 Self {
26 from: cli
27 .from
28 .or(conf.from)
29 .unwrap_or_else(|| String::from("markdown-raw_tex")),
30 to: cli.to.or(conf.to).unwrap_or_else(|| String::from("html")),
31 pandoc_filters: conf.pandoc_filters,
18 inlines: conf.inlines.unwrap_or_else(default_inlines), 32 inlines: conf.inlines.unwrap_or_else(default_inlines),
19 } 33 }
20 } 34 }
21} 35}
22 36
23fn default_inlines() -> HashMap<String, HashMap<String, HashSet<String>>> { 37fn default_inlines() -> Inlines {
24 let mut clang = HashMap::new(); 38 let mut clang = HashMap::new();
25 let mut clang_inline_children = HashSet::new(); 39 let mut clang_inline_children = HashSet::new();
26 // TODO: this is not great: no differences between variable/field for children, but differences 40 clang_inline_children.insert(ChildrenKind(String::from("variables")));
27 // as a parent... 41 clang_inline_children.insert(ChildrenKind(String::from("fields")));
28 clang_inline_children.insert(String::from("variable")); 42 clang_inline_children.insert(ChildrenKind(String::from("functions")));
29 //classes.insert(String::from("field")); 43 clang_inline_children.insert(ChildrenKind(String::from("methods")));
30 clang_inline_children.insert(String::from("function")); 44 clang.insert(
31 //classes.insert(String::from("method")); 45 EntityKind(String::from("struct")),
32 clang.insert(String::from("struct"), clang_inline_children.clone()); 46 clang_inline_children.clone(),
33 clang.insert(String::from("class"), clang_inline_children.clone()); 47 );
34 clang.insert(String::from("namespace"), clang_inline_children); 48 clang.insert(
49 EntityKind(String::from("class")),
50 clang_inline_children.clone(),
51 );
52 clang.insert(EntityKind(String::from("namespace")), clang_inline_children);
35 53
36 let mut inlines = HashMap::new(); 54 let mut inlines = HashMap::new();
37 inlines.insert(String::from("clang"), clang); 55 inlines.insert(Language::Clang, clang);
38 56
39 inlines 57 inlines
40} 58}
@@ -48,6 +66,12 @@ impl Default for Config {
48#[derive(Debug, Clone, Default, StructOpt, Deserialize, Serialize)] 66#[derive(Debug, Clone, Default, StructOpt, Deserialize, Serialize)]
49#[serde(rename_all = "kebab-case")] 67#[serde(rename_all = "kebab-case")]
50pub(crate) struct ProvidedConfig { 68pub(crate) struct ProvidedConfig {
69 #[structopt(long = "generator-from")]
70 pub(super) from: Option<String>,
71 #[structopt(long = "generator-to")]
72 pub(super) to: Option<String>,
73 #[structopt(long = "generator-pandoc-filters", number_of_values = 1)]
74 pub(super) pandoc_filters: Vec<String>,
51 #[structopt(skip)] 75 #[structopt(skip)]
52 pub(crate) inlines: Option<HashMap<String, HashMap<String, HashSet<String>>>>, 76 pub(super) inlines: Option<Inlines>,
53} 77}
diff --git a/src/generator/mod.rs b/src/generator/mod.rs
index b4e1c94..3f62779 100644
--- a/src/generator/mod.rs
+++ b/src/generator/mod.rs
@@ -2,11 +2,8 @@ pub(crate) mod config;
2mod pandoc; 2mod pandoc;
3 3
4use self::config::Config; 4use self::config::Config;
5//use crate::entities::{
6// Description, DynEntity, EntitiesManager, EntitiesManagerComponents, Usr,
7//};
8use self::pandoc::into_pandoc; 5use self::pandoc::into_pandoc;
9use crate::types::Entity; 6use crate::types::*;
10 7
11use anyhow::{ensure, Context, Result}; 8use anyhow::{ensure, Context, Result};
12use rayon::Scope; 9use rayon::Scope;
@@ -18,7 +15,11 @@ use std::path::Path;
18 15
19const DEFAULT_CSS: &[u8] = include_bytes!("../../res/style.css"); 16const DEFAULT_CSS: &[u8] = include_bytes!("../../res/style.css");
20 17
21pub(crate) fn generate(base_dir: &Path, entities: BTreeMap<String, Entity>, config: &Config) -> Result<()> { 18pub(crate) fn generate(
19 base_dir: &Path,
20 entities: BTreeMap<EntityId, Entity>,
21 config: &Config,
22) -> Result<()> {
22 let md_output_dir = base_dir.join("markdown"); 23 let md_output_dir = base_dir.join("markdown");
23 let html_output_dir = base_dir.join("html"); 24 let html_output_dir = base_dir.join("html");
24 25
@@ -54,7 +55,7 @@ pub(crate) fn generate(base_dir: &Path, entities: BTreeMap<String, Entity>, conf
54} 55}
55 56
56fn generate_recursively<'a>( 57fn generate_recursively<'a>(
57 id: String, 58 id: EntityId,
58 entity: Entity, 59 entity: Entity,
59 pool: &Scope<'a>, 60 pool: &Scope<'a>,
60 md_output_dir: &'a Path, 61 md_output_dir: &'a Path,
@@ -63,7 +64,7 @@ fn generate_recursively<'a>(
63 config: &'a Config, 64 config: &'a Config,
64) { 65) {
65 pool.spawn(move |pool| { 66 pool.spawn(move |pool| {
66 trace!("Trying to generate {}", id); 67 trace!("Trying to generate {}", id.0);
67 68
68 let leftovers = generate_single( 69 let leftovers = generate_single(
69 &id, 70 &id,
@@ -90,18 +91,18 @@ fn generate_recursively<'a>(
90} 91}
91 92
92fn generate_single( 93fn generate_single(
93 id: &str, 94 id: &EntityId,
94 entity: Entity, 95 entity: Entity,
95 md_output_dir: impl AsRef<Path>, 96 md_output_dir: impl AsRef<Path>,
96 html_output_dir: impl AsRef<Path>, 97 html_output_dir: impl AsRef<Path>,
97 css_path: impl AsRef<Path>, 98 css_path: impl AsRef<Path>,
98 config: &Config 99 config: &Config,
99) -> Result<BTreeMap<String, Entity>> { 100) -> Result<BTreeMap<EntityId, Entity>> {
100 use std::io::prelude::*; 101 use std::io::prelude::*;
101 use std::process::{Command, Stdio}; 102 use std::process::{Command, Stdio};
102 103
103 let md_output_file = md_output_dir.as_ref().join(id); 104 let md_output_file = md_output_dir.as_ref().join(&id.0);
104 let html_output_file = html_output_dir.as_ref().join(id); 105 let html_output_file = html_output_dir.as_ref().join(&id.0);
105 106
106 let mut command = Command::new("pandoc"); 107 let mut command = Command::new("pandoc");
107 108
@@ -111,7 +112,10 @@ fn generate_single(
111 .stderr(Stdio::piped()) 112 .stderr(Stdio::piped())
112 .args(&[ 113 .args(&[
113 "--from=json", 114 "--from=json",
114 "--to=markdown", 115 // standalone keeps the sent metadat
116 "--standalone",
117 "--to",
118 &config.from,
115 "--output", 119 "--output",
116 md_output_file 120 md_output_file
117 .to_str() 121 .to_str()
@@ -165,8 +169,10 @@ fn generate_single(
165 .stdout(Stdio::piped()) 169 .stdout(Stdio::piped())
166 .stderr(Stdio::piped()) 170 .stderr(Stdio::piped())
167 .args(&[ 171 .args(&[
168 "--from=markdown-raw_tex", 172 "--from",
169 "--to=html", 173 &config.from,
174 "--to",
175 &config.to,
170 "--css", 176 "--css",
171 css_path 177 css_path
172 .as_ref() 178 .as_ref()
@@ -183,6 +189,10 @@ fn generate_single(
183 .context("Entity name is not valid UTF-8")?, 189 .context("Entity name is not valid UTF-8")?,
184 ]); 190 ]);
185 191
192 for filter in &config.pandoc_filters {
193 command.args(&["--filter", filter]);
194 }
195
186 let command_str = format!("{:?}", command); 196 let command_str = format!("{:?}", command);
187 debug!("Launching command: {}", command_str); 197 debug!("Launching command: {}", command_str);
188 198
@@ -190,6 +200,8 @@ fn generate_single(
190 .output() 200 .output()
191 .context("Failed to execute Pandoc command")?; 201 .context("Failed to execute Pandoc command")?;
192 202
203 std::io::stderr().lock().write_all(&output.stderr)?;
204
193 ensure!( 205 ensure!(
194 output.status.success(), 206 output.status.success(),
195 CommandError { 207 CommandError {
diff --git a/src/generator/pandoc.rs b/src/generator/pandoc.rs
index 1753d34..035acab 100644
--- a/src/generator/pandoc.rs
+++ b/src/generator/pandoc.rs
@@ -1,14 +1,11 @@
1use super::config::Config; 1use super::config::Config;
2use crate::types::Entity; 2use crate::types::*;
3 3
4use pandoc_types::definition::{Attr, Block, Inline, Meta, MetaValue, Pandoc}; 4use pandoc_types::definition::{Attr, Block, Inline, Meta, MetaValue, Pandoc};
5 5
6use std::collections::BTreeMap; 6use std::collections::BTreeMap;
7 7
8pub(crate) fn into_pandoc( 8pub(crate) fn into_pandoc(entity: Entity, config: &Config) -> (Pandoc, BTreeMap<EntityId, Entity>) {
9 entity: Entity,
10 config: &Config,
11) -> (Pandoc, BTreeMap<String, Entity>) {
12 let mut meta = Meta::null(); 9 let mut meta = Meta::null();
13 10
14 let title = vec![Inline::Code(Attr::null(), entity.name.clone())]; 11 let title = vec![Inline::Code(Attr::null(), entity.name.clone())];
@@ -57,7 +54,7 @@ pub(crate) fn into_pandoc(
57 content.push(Block::Header( 54 content.push(Block::Header(
58 2, 55 2,
59 Attr::null(), 56 Attr::null(),
60 vec![Inline::Str(String::from(section_name))], 57 vec![Inline::Str(section_name.0.clone())],
61 )); 58 ));
62 59
63 content.push(members_list); 60 content.push(members_list);
@@ -71,7 +68,7 @@ pub(crate) fn into_pandoc(
71 content.push(Block::Header( 68 content.push(Block::Header(
72 2, 69 2,
73 Attr::null(), 70 Attr::null(),
74 vec![Inline::Str(section_name.clone())], 71 vec![Inline::Str(section_name.0.clone())],
75 )); 72 ));
76 73
77 content.push(members_list); 74 content.push(members_list);
@@ -79,7 +76,7 @@ pub(crate) fn into_pandoc(
79 embedded_documentation.push(Block::Header( 76 embedded_documentation.push(Block::Header(
80 2, 77 2,
81 Attr::null(), 78 Attr::null(),
82 vec![Inline::Str(section_name + " Documentation")], 79 vec![Inline::Str(section_name.0 + " Documentation")],
83 )); 80 ));
84 81
85 for (_id, child) in children { 82 for (_id, child) in children {
@@ -112,7 +109,7 @@ fn str_block(content: String) -> Block {
112 Block::Plain(vec![Inline::Str(content)]) 109 Block::Plain(vec![Inline::Str(content)])
113} 110}
114 111
115fn entity_link(id: &str, name: String) -> Inline { 112fn entity_link(id: &EntityId, name: String) -> Inline {
116 use pandoc_types::definition::Target; 113 use pandoc_types::definition::Target;
117 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; 114 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
118 115
@@ -135,7 +132,7 @@ fn entity_link(id: &str, name: String) -> Inline {
135 vec![Inline::Code(Attr::null(), name)], 132 vec![Inline::Code(Attr::null(), name)],
136 Target( 133 Target(
137 once("./") 134 once("./")
138 .chain(utf8_percent_encode(id, FRAGMENT)) 135 .chain(utf8_percent_encode(&id.0, FRAGMENT))
139 .collect(), 136 .collect(),
140 String::new(), 137 String::new(),
141 ), 138 ),
@@ -147,7 +144,7 @@ fn raw_markdown(text: String) -> Block {
147 Block::RawBlock(Format(String::from("markdown")), text) 144 Block::RawBlock(Format(String::from("markdown")), text)
148} 145}
149 146
150fn member_list<'a>(members: impl IntoIterator<Item = (&'a String, &'a Entity)>) -> Option<Block> { 147fn member_list<'a>(members: impl IntoIterator<Item = (&'a EntityId, &'a Entity)>) -> Option<Block> {
151 let definitions: Vec<(Vec<Inline>, Vec<Vec<Block>>)> = members 148 let definitions: Vec<(Vec<Inline>, Vec<Vec<Block>>)> = members
152 .into_iter() 149 .into_iter()
153 .map(|(id, entity)| { 150 .map(|(id, entity)| {
diff --git a/src/main.rs b/src/main.rs
index b42d73c..5c613e0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,7 @@
3mod cli; 3mod cli;
4mod config; 4mod config;
5mod generator; 5mod generator;
6mod parsing; 6mod parser;
7mod types; 7mod types;
8 8
9#[macro_use] 9#[macro_use]
@@ -87,12 +87,17 @@ fn start(codemap: &mut CodeMap) -> Result<()> {
87 //let file = file.clone(); 87 //let file = file.clone();
88 let config = load_effective_config(cli, codemap)?; 88 let config = load_effective_config(cli, codemap)?;
89 89
90 let entities = parsing::clang::parse_compile_commands(&config.clang, codemap)?; 90 let entities = parser::clang::parse_compile_commands(&config.clang, codemap)?;
91 //let manager = parse_file(file, &config.extra_clang_args); 91 //let manager = parse_file(file, &config.extra_clang_args);
92 92
93 let base_output_dir = std::path::Path::new("doc"); 93 let base_output_dir = std::path::Path::new("doc");
94 generate(&base_output_dir, entities, &config.generator)?; 94 generate(&base_output_dir, entities, &config.generator)?;
95 } 95 }
96 Command::Inspect => {
97 let config = load_effective_config(cli, codemap)?;
98 let entities = parser::clang::parse_compile_commands(&config.clang, codemap)?;
99 serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?;
100 }
96 Command::Config { 101 Command::Config {
97 command: ConfigCommand::Default, 102 command: ConfigCommand::Default,
98 } => { 103 } => {
diff --git a/src/parsing/clang/config.rs b/src/parser/clang/config.rs
index cb05876..05fe3ab 100644
--- a/src/parsing/clang/config.rs
+++ b/src/parser/clang/config.rs
@@ -7,18 +7,18 @@ use std::path::PathBuf;
7#[derive(Debug, Clone, StructOpt, Deserialize, Serialize)] 7#[derive(Debug, Clone, StructOpt, Deserialize, Serialize)]
8#[serde(rename_all = "kebab-case")] 8#[serde(rename_all = "kebab-case")]
9pub(crate) struct Config { 9pub(crate) struct Config {
10 pub(crate) compile_commands_location: PathBuf, 10 pub(super) compile_commands_location: PathBuf,
11 pub(crate) extra_args: Vec<String>, 11 pub(super) extra_args: Vec<String>,
12} 12}
13 13
14#[derive(Debug, Clone, Default, StructOpt, Deserialize, Serialize)] 14#[derive(Debug, Clone, Default, StructOpt, Deserialize, Serialize)]
15#[serde(rename_all = "kebab-case")] 15#[serde(rename_all = "kebab-case")]
16pub(crate) struct ProvidedConfig { 16pub(crate) struct ProvidedConfig {
17 #[structopt(long = "clang-compile-commands-location")] 17 #[structopt(long = "clang-compile-commands-location")]
18 pub(crate) compile_commands_location: Option<PathBuf>, 18 pub(super) compile_commands_location: Option<PathBuf>,
19 #[structopt(long = "clang-extra-args", number_of_values = 1)] 19 #[structopt(long = "clang-extra-args", number_of_values = 1)]
20 #[serde(default)] 20 #[serde(default)]
21 pub(crate) extra_args: Vec<String>, 21 pub(super) extra_args: Vec<String>,
22} 22}
23 23
24impl Default for Config { 24impl Default for Config {
diff --git a/src/parsing/clang/entities.rs b/src/parser/clang/entities.rs
index a8062bb..41fe061 100644
--- a/src/parsing/clang/entities.rs
+++ b/src/parser/clang/entities.rs
@@ -1,4 +1,4 @@
1use crate::types::Entity; 1use crate::types::*;
2 2
3use clang::{EntityKind, Usr}; 3use clang::{EntityKind, Usr};
4use thiserror::Error; 4use thiserror::Error;
@@ -16,7 +16,7 @@ pub(super) struct Children {
16 functions: Option<BTreeMap<Usr, Described<Function>>>, 16 functions: Option<BTreeMap<Usr, Described<Function>>>,
17} 17}
18 18
19#[derive(Debug, Clone, PartialEq, Eq)] 19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub(super) enum ClangEntityKind { 20pub(super) enum ClangEntityKind {
21 Namespace, 21 Namespace,
22 Variable(VariableKind), 22 Variable(VariableKind),
@@ -24,24 +24,50 @@ pub(super) enum ClangEntityKind {
24 Function(FunctionKind), 24 Function(FunctionKind),
25} 25}
26 26
27#[derive(Debug, Clone, PartialEq, Eq)] 27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub(super) enum VariableKind { 28pub(super) enum VariableKind {
29 Variable, 29 Variable,
30 Field, 30 Field,
31} 31}
32 32
33#[derive(Debug, Clone, PartialEq, Eq)] 33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub(super) enum StructKind { 34pub(super) enum StructKind {
35 Struct, 35 Struct,
36 Class, 36 Class,
37} 37}
38 38
39#[derive(Debug, Clone, PartialEq, Eq)] 39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub(super) enum FunctionKind { 40pub(super) enum FunctionKind {
41 Function, 41 Function,
42 Method, 42 Method,
43} 43}
44 44
45impl ClangEntityKind {
46 fn to_str_singular(self) -> &'static str {
47 match self {
48 ClangEntityKind::Namespace => "namespace",
49 ClangEntityKind::Variable(VariableKind::Variable) => "variable",
50 ClangEntityKind::Variable(VariableKind::Field) => "field",
51 ClangEntityKind::Struct(StructKind::Struct) => "struct",
52 ClangEntityKind::Struct(StructKind::Class) => "class",
53 ClangEntityKind::Function(FunctionKind::Function) => "function",
54 ClangEntityKind::Function(FunctionKind::Method) => "method",
55 }
56 }
57
58 fn to_str_plural(self) -> &'static str {
59 match self {
60 ClangEntityKind::Namespace => "namespaces",
61 ClangEntityKind::Variable(VariableKind::Variable) => "variables",
62 ClangEntityKind::Variable(VariableKind::Field) => "fields",
63 ClangEntityKind::Struct(StructKind::Struct) => "structs",
64 ClangEntityKind::Struct(StructKind::Class) => "classes",
65 ClangEntityKind::Function(FunctionKind::Function) => "functions",
66 ClangEntityKind::Function(FunctionKind::Method) => "methods",
67 }
68 }
69}
70
45#[derive(Debug, Error)] 71#[derive(Debug, Error)]
46#[error("Unsupported Clang entity kind: {:?}", _0)] 72#[error("Unsupported Clang entity kind: {:?}", _0)]
47pub(super) struct TryFromEntityKindError(String); 73pub(super) struct TryFromEntityKindError(String);
@@ -66,7 +92,7 @@ impl TryFrom<EntityKind> for ClangEntityKind {
66} 92}
67 93
68pub(super) trait ClangEntity { 94pub(super) trait ClangEntity {
69 fn kind(&self) -> &'static str; 95 fn kind(&self) -> ClangEntityKind;
70 96
71 fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> { 97 fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> {
72 None 98 None
@@ -145,54 +171,58 @@ where
145 171
146impl<T: ClangEntity> From<Described<T>> for Entity { 172impl<T: ClangEntity> From<Described<T>> for Entity {
147 fn from(entity: Described<T>) -> Self { 173 fn from(entity: Described<T>) -> Self {
148 let mut children = BTreeMap::new(); 174 let mut children: BTreeMap<ChildrenKind, BTreeMap<EntityId, Entity>> = BTreeMap::new();
149 175
150 let kind = String::from(entity.entity.kind()); 176 let kind = EntityKind(String::from(entity.entity.kind().to_str_singular()));
151 let clang_children = entity.entity.into_children(); 177 let clang_children = entity.entity.into_children();
152 178
153 if let Some(namespaces) = clang_children.namespaces { 179 if let Some(namespaces) = clang_children.namespaces {
154 children.insert( 180 for (usr, namespace) in namespaces {
155 String::from("namespace"), 181 children
156 namespaces 182 .entry(ChildrenKind(String::from(
157 .into_iter() 183 namespace.entity.kind().to_str_plural(),
158 .map(|(usr, namespace)| (usr.0, namespace.into())) 184 )))
159 .collect(), 185 .or_default()
160 ); 186 .insert(EntityId(usr.0), namespace.into());
187 }
161 } 188 }
162 189
163 if let Some(variables) = clang_children.variables { 190 if let Some(variables) = clang_children.variables {
164 children.insert( 191 for (usr, variable) in variables {
165 String::from("variable"), 192 children
166 variables 193 .entry(ChildrenKind(String::from(
167 .into_iter() 194 variable.entity.kind().to_str_plural(),
168 .map(|(usr, variable)| (usr.0, variable.into())) 195 )))
169 .collect(), 196 .or_default()
170 ); 197 .insert(EntityId(usr.0), variable.into());
198 }
171 } 199 }
172 200
173 if let Some(structs) = clang_children.structs { 201 if let Some(structs) = clang_children.structs {
174 children.insert( 202 for (usr, r#struct) in structs {
175 String::from("struct"), 203 children
176 structs 204 .entry(ChildrenKind(String::from(
177 .into_iter() 205 r#struct.entity.kind().to_str_plural(),
178 .map(|(usr, the_struct)| (usr.0, the_struct.into())) 206 )))
179 .collect(), 207 .or_default()
180 ); 208 .insert(EntityId(usr.0), r#struct.into());
209 }
181 } 210 }
182 211
183 if let Some(functions) = clang_children.functions { 212 if let Some(functions) = clang_children.functions {
184 children.insert( 213 for (usr, function) in functions {
185 String::from("function"), 214 children
186 functions 215 .entry(ChildrenKind(String::from(
187 .into_iter() 216 function.entity.kind().to_str_plural(),
188 .map(|(usr, function)| (usr.0, function.into())) 217 )))
189 .collect(), 218 .or_default()
190 ); 219 .insert(EntityId(usr.0), function.into());
220 }
191 } 221 }
192 222
193 Entity { 223 Entity {
194 name: entity.description.name, 224 name: entity.description.name,
195 language: String::from("clang"), 225 language: Language::Clang,
196 kind, 226 kind,
197 brief_description: entity.description.brief, 227 brief_description: entity.description.brief,
198 documentation: entity.description.detailed, 228 documentation: entity.description.detailed,
@@ -223,8 +253,8 @@ pub(super) struct Namespace {
223} 253}
224 254
225impl ClangEntity for Namespace { 255impl ClangEntity for Namespace {
226 fn kind(&self) -> &'static str { 256 fn kind(&self) -> ClangEntityKind {
227 "namespace" 257 ClangEntityKind::Namespace
228 } 258 }
229 259
230 fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> { 260 fn get_member_namespaces(&mut self) -> Option<&mut BTreeMap<Usr, Described<Namespace>>> {
@@ -268,11 +298,8 @@ pub(super) struct Variable {
268} 298}
269 299
270impl ClangEntity for Variable { 300impl ClangEntity for Variable {
271 fn kind(&self) -> &'static str { 301 fn kind(&self) -> ClangEntityKind {
272 match self.kind { 302 ClangEntityKind::Variable(self.kind)
273 VariableKind::Variable => "variable",
274 VariableKind::Field => "field",
275 }
276 } 303 }
277} 304}
278 305
@@ -297,11 +324,8 @@ pub(super) struct Struct {
297} 324}
298 325
299impl ClangEntity for Struct { 326impl ClangEntity for Struct {
300 fn kind(&self) -> &'static str { 327 fn kind(&self) -> ClangEntityKind {
301 match self.kind { 328 ClangEntityKind::Struct(self.kind)
302 StructKind::Struct => "struct",
303 StructKind::Class => "class",
304 }
305 } 329 }
306 330
307 fn get_member_variables(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> { 331 fn get_member_variables(&mut self) -> Option<&mut BTreeMap<Usr, Described<Variable>>> {
@@ -343,11 +367,8 @@ pub(super) struct Function {
343} 367}
344 368
345impl ClangEntity for Function { 369impl ClangEntity for Function {
346 fn kind(&self) -> &'static str { 370 fn kind(&self) -> ClangEntityKind {
347 match self.kind { 371 ClangEntityKind::Function(self.kind)
348 FunctionKind::Function => "function",
349 FunctionKind::Method => "method",
350 }
351 } 372 }
352} 373}
353 374
diff --git a/src/parsing/clang/mod.rs b/src/parser/clang/mod.rs
index 047c49e..047c49e 100644
--- a/src/parsing/clang/mod.rs
+++ b/src/parser/clang/mod.rs
diff --git a/src/parsing/clang/parsing.rs b/src/parser/clang/parsing.rs
index 5359253..a654681 100644
--- a/src/parsing/clang/parsing.rs
+++ b/src/parser/clang/parsing.rs
@@ -1,6 +1,6 @@
1use super::config::Config; 1use super::config::Config;
2use super::entities::*; 2use super::entities::*;
3use crate::types::Entity; 3use crate::types::*;
4 4
5use anyhow::{anyhow, Context, Error, Result}; 5use anyhow::{anyhow, Context, Error, Result};
6use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr}; 6use clang::{Clang, CompilationDatabase, Index, TranslationUnit, Usr};
@@ -208,7 +208,7 @@ impl FromTopLevel for Struct {
208pub(crate) fn parse_compile_commands( 208pub(crate) fn parse_compile_commands(
209 config: &Config, 209 config: &Config,
210 codemap: &mut CodeMap, 210 codemap: &mut CodeMap,
211) -> Result<BTreeMap<String, Entity>> { 211) -> Result<BTreeMap<EntityId, Entity>> {
212 let clang = Clang::new().unwrap(); 212 let clang = Clang::new().unwrap();
213 let index = Index::new( 213 let index = Index::new(
214 &clang, /* exclude from pch = */ false, /* print diagnostics = */ false, 214 &clang, /* exclude from pch = */ false, /* print diagnostics = */ false,
@@ -280,10 +280,25 @@ pub(crate) fn parse_compile_commands(
280 let normalized_entities = entities 280 let normalized_entities = entities
281 .namespaces 281 .namespaces
282 .into_iter() 282 .into_iter()
283 .map(|(usr, entity)| (usr.0, entity.into())) 283 .map(|(usr, entity)| (EntityId(usr.0), entity.into()))
284 .chain(entities.variables.into_iter().map(|(usr, entity)| (usr.0, entity.into()))) 284 .chain(
285 .chain(entities.structs.into_iter().map(|(usr, entity)| (usr.0, entity.into()))) 285 entities
286 .chain(entities.functions.into_iter().map(|(usr, entity)| (usr.0, entity.into()))) 286 .variables
287 .into_iter()
288 .map(|(usr, entity)| (EntityId(usr.0), entity.into())),
289 )
290 .chain(
291 entities
292 .structs
293 .into_iter()
294 .map(|(usr, entity)| (EntityId(usr.0), entity.into())),
295 )
296 .chain(
297 entities
298 .functions
299 .into_iter()
300 .map(|(usr, entity)| (EntityId(usr.0), entity.into())),
301 )
287 .collect(); 302 .collect();
288 303
289 Ok(normalized_entities) 304 Ok(normalized_entities)
@@ -463,11 +478,12 @@ fn add_entity(
463 }; 478 };
464 479
465 if let Some(in_tree_entity) = toplevel.get_entity_mut(libclang_entity) { 480 if let Some(in_tree_entity) = toplevel.get_entity_mut(libclang_entity) {
466 // if current.has_documentation && !tree.has_documentation { 481 // if current.has_documentation && !tree.has_documentation {
467 // append_documentation 482 // append_documentation
468 // } 483 // }
469 } else if libclang_entity.is_definition() { 484 } else if libclang_entity.is_definition() {
470 // TODO: This probably means that you can't put documentation in forward declarations. 485 // TODO: This probably means that you can't put documentation in forward declarations.
486 // TODO: Ad-hoc toplevel functions are not documented
471 // 487 //
472 // This seems restrictive, but since there can be multiple declarations but only one definition, 488 // This seems restrictive, but since there can be multiple declarations but only one definition,
473 // you should probably put your documentation on the definition anyway? 489 // you should probably put your documentation on the definition anyway?
diff --git a/src/parsing/mod.rs b/src/parser/mod.rs
index 0736eee..0736eee 100644
--- a/src/parsing/mod.rs
+++ b/src/parser/mod.rs
diff --git a/src/types.rs b/src/types.rs
index 82f9c65..f378f8b 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,22 +1,80 @@
1use serde_derive::{Serialize, Deserialize}; 1use serde_derive::{Serialize, Deserialize};
2use thiserror::Error;
2 3
3use std::collections::BTreeMap; 4use std::collections::BTreeMap;
5use std::str::FromStr;
4 6
5#[derive(Debug, Clone, Serialize, Deserialize)] 7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct Poseidoc { 8pub struct Poseidoc {
7 pub config: toml::Value, 9 pub config: toml::Value,
8 pub entities: BTreeMap<String, Entity>, 10 pub entities: BTreeMap<String, Entity>,
9} 11}
10 12
11#[derive(Debug, Clone, Serialize, Deserialize)] 13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct Entity { 14pub struct Entity {
13 pub name: String, 15 pub name: String,
14 //location: SourceLocation 16 //location: SourceLocation
15 pub language: String, 17 pub language: Language,
16 pub kind: String, 18 pub kind: EntityKind,
17 pub brief_description: String, 19 pub brief_description: String,
18 pub documentation: String, 20 pub documentation: String,
19 pub children: BTreeMap<String, BTreeMap<String, Entity>>, 21 pub children: BTreeMap<ChildrenKind, BTreeMap<EntityId, Entity>>,
20} 22}
21 23
22// TODO: use newtype for language, entity kind, entity ID 24// TODO: use newtype for entity kind, entity ID
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27#[serde(try_from = "&str", into = "&'static str")]
28pub enum Language {
29 Clang,
30}
31
32impl std::fmt::Display for Language {
33 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34 write!(f, "{}", <&'static str>::from(*self))
35 }
36}
37
38impl FromStr for Language {
39 type Err = LanguageParseError;
40
41 fn from_str(s: &str) -> Result<Self, Self::Err> {
42 match s {
43 "clang" => Ok(Language::Clang),
44 _ => Err(LanguageParseError(())),
45 }
46 }
47}
48
49impl std::convert::TryFrom<&str> for Language {
50 type Error = LanguageParseError;
51 fn try_from(s: &str) -> Result<Language, Self::Error> {
52 Language::from_str(s)
53 }
54}
55
56impl From<Language> for &'static str {
57 fn from(lang: Language) -> &'static str {
58 match lang {
59 Language::Clang => "clang",
60 }
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
65#[error("invalid language")]
66pub struct LanguageParseError(());
67
68#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
69#[serde(transparent)]
70pub struct EntityKind(pub String);
71
72// Plural version of EntityKind
73
74#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
75#[serde(transparent)]
76pub struct ChildrenKind(pub String);
77
78#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
79#[serde(transparent)]
80pub struct EntityId(pub String);