Skip to content

Commit

Permalink
Add support for simultaneous output of >1 language
Browse files Browse the repository at this point in the history
Author: @ptaoussanis

- This implementation attempts to be minimally invasive.
  Most of the logical changes are within `html/write-index` and
  `html/write-namespaces`, where a special path is introduced
  for cross-platform projects.

- NO behavioural changes are intended for traditional
  (non-cross-platform) projects.

- See weavejester#216 for detailed feature discussion.
  • Loading branch information
ptaoussanis committed Jul 6, 2023
1 parent 6e2a89d commit f88c2d9
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 34 deletions.
24 changes: 23 additions & 1 deletion codox/resources/codox/theme/default/css/default.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ h5.license {
right: 0;
height: 22px;
color: #f5f5f5;
padding: 5px 7px;
padding: 7px 10px;
}

#content {
Expand Down Expand Up @@ -97,6 +97,8 @@ h5.license {
}

#header h1 {
display: block;
float: left;
margin: 0;
padding: 0;
font-size: 18px;
Expand All @@ -121,6 +123,26 @@ h5.license {
color: #f5f5f5;
}

#langs {
display: block;
float: left;
font-size: 16px;
margin: 0 10px;
}

#langs .lang {
display: inline-block;
margin: 0 2px;
padding: 0 7px;
background-color: #717171;
border-radius: 6px;
vertical-align: middle;
}

#langs .lang.current {
background-color: #a33;
}

.sidebar a {
color: #333;
}
Expand Down
38 changes: 31 additions & 7 deletions codox/src/codox/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,25 @@
namespaces))

(defn- read-namespaces
"Returns {<language> <namespace-seq>} for cross-platform opts,
or <namespace-seq> otherwise."
[{:keys [language root-path source-paths namespaces metadata exclude-vars] :as opts}]
(let [reader (namespace-readers language)]
(-> (reader source-paths (select-keys opts [:exception-handler]))
(filter-namespaces namespaces)
(remove-excluded-vars exclude-vars)
(add-source-paths root-path source-paths)
(add-ns-defaults metadata))))
(if (:cross-platform? opts)
(reduce
(fn [m language]
(assoc m language
(read-namespaces
(assoc opts
:language language
:cross-platform? false))))
{}
(:languages opts))
(let [reader (namespace-readers language)]
(-> (reader source-paths (select-keys opts [:exception-handler]))
(filter-namespaces namespaces)
(remove-excluded-vars exclude-vars)
(add-source-paths root-path source-paths)
(add-ns-defaults metadata)))))

(defn- read-documents [{:keys [doc-paths doc-files] :or {doc-files :all}}]
(cond
Expand Down Expand Up @@ -113,12 +125,24 @@
:themes [:default]
:git-commit (delay (git-commit root-path))}))

(defn- cross-platform-options [{:keys [language] :as opts}]
(if-not (set? language)
opts ; {:language <keyword>}
(if (= (count language) 1)
(assoc opts :language (first language)) ; {:language <keyword>}

;; Cross-platform case: {:language nil, :languages <set>}
(assoc opts
:language nil
:languages language
:cross-platform? true))))

(defn generate-docs
"Generate documentation from source files."
([]
(generate-docs {}))
([options]
(let [options (merge defaults options)
(let [options (-> (merge defaults options) cross-platform-options)
write-fn (writer options)
namespaces (read-namespaces options)
documents (read-documents options)]
Expand Down
148 changes: 122 additions & 26 deletions codox/src/codox/writer/html.clj
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,25 @@
(if-let [doc (:doc metadata)]
(markdown-to-html doc project ns))])

(defn- language-info
[language]
(when language
(case language
:clojure {:ext "clj", :filename-suffix ".clj", :name "Clojure"}
:clojurescript {:ext "cljs", :filename-suffix ".cljs", :name "ClojureScript"}
(ex-info (str "Unexpected language: `" language "`")
{:language language}))))

(defn- index-filename [language]
(str "index" (:filename-suffix (language-info language)) ".html"))

(defn- ns-filename [namespace]
(str (:name namespace) ".html"))
(str (:name namespace)
(:filename-suffix (language-info (:language namespace)))
".html"))

(comment
(ns-filename {:name 'my-ns :language :clojure}))

(defn- ns-filepath [output-dir namespace]
(str output-dir "/" (ns-filename namespace)))
Expand Down Expand Up @@ -235,11 +252,12 @@
[:span.bottom]])))

(defn- index-link [project on-index?]
(list
[:h3.no-link [:span.inner "Project"]]
[:ul.index-link
[:li.depth-1 {:class (if on-index? "current")}
(link-to "index.html" [:div.inner "Index"])]]))
(when-not (:cross-platform? project)
(list
[:h3.no-link [:span.inner "Project"]]
[:ul.index-link
[:li.depth-1 {:class (if on-index? "current")}
(link-to "index.html" [:div.inner "Index"])]])))

(defn- topics-menu [project current-doc]
(if-let [docs (seq (:documents project))]
Expand Down Expand Up @@ -275,16 +293,28 @@
(get-in project [:html :namespace-list] default)))

(defn- namespaces-menu [project current-ns]
(let [namespaces (:namespaces project)]
(when (:show-namespaces? project)
(let [namespaces (:namespaces project)]
(list
[:h3.no-link [:span.inner "Namespaces"]]
(case (namespace-list-type project)
:flat (flat-namespaces namespaces current-ns)
:nested (nested-namespaces namespaces current-ns))))))

(defn- platforms-menu [project]
(when (:show-platforms? project)
(list
[:h3.no-link [:span.inner "Namespaces"]]
(case (namespace-list-type project)
:flat (flat-namespaces namespaces current-ns)
:nested (nested-namespaces namespaces current-ns)))))
[:h3.no-link [:span.inner "Platforms"]]
[:ul.index-link
(for [language (:languages project)]
[:li.depth-1
(link-to (index-filename language)
[:div.inner (:name (language-info language))])])])))

(defn- primary-sidebar [project & [current]]
[:div.sidebar.primary
(index-link project (nil? current))
(platforms-menu project)
(topics-menu project current)
(namespaces-menu project current)])

Expand Down Expand Up @@ -314,10 +344,20 @@
[:span.project-name (h (:name project))] " "
[:span.project-version (h (:version project))]])

(defn- header-platforms [project]
(when (:cross-platform? project)
(let [{:keys [language languages]} project]
[:div#langs
(for [language* languages]
(if (= language language*)
[:div.lang.current (:ext (language-info language*))]
[:div.lang (link-to (index-filename language*) (:ext (language-info language*)))]))])))

(defn- header [project]
[:div#header
[:h2 "Generated by " (link-to "https://github.com/weavejester/codox" "Codox")]
[:h1 (link-to "index.html" (project-title project))]])
[:h1 (link-to "index.html" (project-title project))]
(header-platforms project)])

(defn- package [project]
(if-let [p (:package project)]
Expand Down Expand Up @@ -360,16 +400,28 @@
[:ul.topics
(for [doc docs]
[:li (link-to (doc-filename doc) (h (:title doc)))])]))
[:h2 "Namespaces"]
(for [namespace (sort-by :name (:namespaces project))]
[:div.namespace
[:h3 (link-to (ns-filename namespace) (h (:name namespace)))]
[:div.doc (format-docstring project nil (update-in namespace [:doc] util/summary))]
[:div.index
[:p "Public variables and functions:"]
(unordered-list
(for [var (sorted-public-vars namespace)]
(list " " (link-to (var-uri namespace var) (h (:name var))) " ")))]])]]))

(when (:show-platforms? project)
(list
[:h2 "Platforms"]
[:p "This project includes code for multiple platforms, please "
[:strong "choose a platform"] " to view its documentation:"]
[:ul
(for [language (:languages project)]
[:li (link-to (index-filename language) (:name (language-info language)))])]))

(when (:show-namespaces? project)
(list
[:h2 "Namespaces"]
(for [namespace (sort-by :name (:namespaces project))]
[:div.namespace
[:h3 (link-to (ns-filename namespace) (h (:name namespace)))]
[:div.doc (format-docstring project nil (update-in namespace [:doc] util/summary))]
[:div.index
[:p "Public variables and functions:"]
(unordered-list
(for [var (sorted-public-vars namespace)]
(list " " (link-to (var-uri namespace var) (h (:name var))) " ")))]])))]]))

(defmulti format-document
"Format a document into HTML."
Expand Down Expand Up @@ -464,13 +516,57 @@
(doseq [dir dirs]
(.mkdirs (io/file output-dir dir))))

(defn- cross-platform-namespaces
[namespaces language]
(map #(assoc % :language language)
(get namespaces language)))

(defn- write-index [output-dir project]
(spit (io/file output-dir "index.html") (transform-html project (index-page project))))
(let [{:keys [namespaces cross-platform?]} project]

(when cross-platform?
;; Write an index file for each language
(doseq [language (:languages project)]
(let [namespaces (cross-platform-namespaces namespaces language)
project
(assoc project
:namespaces namespaces
:language language
:show-platforms? false
:show-namespaces? true)]
(spit (io/file output-dir (index-filename language))
(transform-html project (index-page project))))))

;; Always write a main index file
(let [project (assoc project
:show-platforms? cross-platform?
:show-namespaces? (not cross-platform?))]
(spit (io/file output-dir (index-filename nil))
(transform-html project (index-page project))))))

(defn- write-namespaces [output-dir project]
(doseq [namespace (:namespaces project)]
(spit (ns-filepath output-dir namespace)
(transform-html project (namespace-page project namespace)))))
(let [{:keys [namespaces cross-platform?]} project]

(if cross-platform?
;; Write namespace files for each language
(doseq [language (:languages project)]
(let [namespaces (cross-platform-namespaces namespaces language)]
(doseq [namespace namespaces]
(let [project (assoc project
:namespaces namespaces
:language language
:show-platforms? false
:show-namespaces? true)]
(spit (ns-filepath output-dir namespace)
(transform-html project (namespace-page project namespace)))))))

;; Write namespace files for only language
(doseq [namespace namespaces]
(let [project (assoc project
:show-platforms? false
:show-namespaces? true)]
(spit (ns-filepath output-dir namespace)
(transform-html project (namespace-page project namespace))))))))

(defn- write-documents [output-dir project]
(doseq [document (:documents project)]
Expand Down

0 comments on commit f88c2d9

Please sign in to comment.