1use std::path::PathBuf;
4
5use crate::{RegisteredDocumentOrigin, list_registered_documents, system_manual_index};
6
7#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
9pub enum AvailableDocumentKind {
10 Markdown,
11 Manual,
12}
13
14#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
16pub enum AvailableDocumentOrigin {
17 User,
18 System,
19 ManualPath,
20}
21
22#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct AvailableDocument {
25 pub name: String,
26 pub kind: AvailableDocumentKind,
27 pub section: Option<String>,
28 pub path: PathBuf,
29 pub origin: AvailableDocumentOrigin,
30}
31
32#[must_use]
34pub fn list_available_documents() -> Vec<AvailableDocument> {
35 list_available_documents_from(list_registered_documents(), system_manual_index().pages())
36}
37
38fn list_available_documents_from(
39 registered: Vec<crate::RegisteredDocument>,
40 manuals: &[crate::ManualPage],
41) -> Vec<AvailableDocument> {
42 let mut documents = registered
43 .into_iter()
44 .map(|document| AvailableDocument {
45 name: document.name,
46 kind: AvailableDocumentKind::Markdown,
47 section: None,
48 path: document.path,
49 origin: match document.origin {
50 RegisteredDocumentOrigin::User => AvailableDocumentOrigin::User,
51 RegisteredDocumentOrigin::System => AvailableDocumentOrigin::System,
52 },
53 })
54 .chain(manuals.iter().map(|page| AvailableDocument {
55 name: page.name.clone(),
56 kind: AvailableDocumentKind::Manual,
57 section: Some(page.section.clone()),
58 path: page.path.clone(),
59 origin: AvailableDocumentOrigin::ManualPath,
60 }))
61 .collect::<Vec<_>>();
62 documents.sort_unstable_by(|left, right| {
63 (&left.name, left.kind, &left.section).cmp(&(&right.name, right.kind, &right.section))
64 });
65 documents
66}
67
68#[cfg(test)]
69mod tests {
70 use std::path::PathBuf;
71
72 use crate::{ManualPage, RegisteredDocument, RegisteredDocumentOrigin};
73
74 use super::{AvailableDocumentKind, AvailableDocumentOrigin, list_available_documents_from};
75
76 #[test]
77 fn merges_both_namespaces_without_hiding_manual_sections() {
78 let documents = list_available_documents_from(
79 vec![RegisteredDocument {
80 name: "printf".to_owned(),
81 path: PathBuf::from("/home/demo/.local/share/mant/documents/printf.md"),
82 origin: RegisteredDocumentOrigin::User,
83 }],
84 &[
85 ManualPage {
86 name: "printf".to_owned(),
87 section: "1".to_owned(),
88 path: PathBuf::from("/usr/share/man/man1/printf.1.gz"),
89 },
90 ManualPage {
91 name: "printf".to_owned(),
92 section: "3".to_owned(),
93 path: PathBuf::from("/usr/share/man/man3/printf.3.gz"),
94 },
95 ],
96 );
97
98 assert_eq!(documents.len(), 3);
99 assert_eq!(documents[0].kind, AvailableDocumentKind::Markdown);
100 assert_eq!(documents[0].origin, AvailableDocumentOrigin::User);
101 assert_eq!(documents[1].section.as_deref(), Some("1"));
102 assert_eq!(documents[2].section.as_deref(), Some("3"));
103 }
104}