diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 457c59ec..6eabaadf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,18 +12,18 @@ jobs: build-clj: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: "Setup Java 17" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' - name: Setup Clojure - uses: DeLaGuardo/setup-clojure@12.1 + uses: DeLaGuardo/setup-clojure@12.3 with: - lein: 2.10.0 + lein: 2.11.1 - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: "m2-${{ hashFiles('project.clj') }}" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..08dbd496 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# CHANGES + +0.9.2 -- 01-31-2024 +* Add `:meta` support to address [#186](https://github.com/clj-commons/marginalia/issues/186). +* Update all dependencies. + +0.9.1 -- 11-08-2017 +* Update to Clojure 1.9.0. + +0.9.0 -- 03-16-2016 +* Bug fixes & documentation updates. + +0.8.0 -- 08-28-2014 +* Improve ClojureScript support, bug fixes, and documentation updates. diff --git a/README.md b/README.md index ecd6404b..81c0eed3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Marginalia 0.9.1 +Marginalia 0.9.2 ================ [![Clojars Project](https://img.shields.io/clojars/v/marginalia.svg)](https://clojars.org/marginalia) @@ -13,7 +13,7 @@ Marginalia is a source code documentation tool that parses Clojure and ClojureSc To get a quick look at what the Marginalia output looks like, [visit the official site](https://clj-commons.org/marginalia/). -**[View the release notes for this version of Marginalia](https://github.com/clj-commons/marginalia/blob/master/docs/release-notes/marginalia-v0.9.1-release-notes.markdown)** +**[View the release notes for this version of Marginalia](https://github.com/clj-commons/marginalia/releases/tag/v0.9.2)** Usage ----- @@ -26,8 +26,8 @@ Currently Marginalia can be used in a number of ways as described below. To use Marginalia with Leiningen add the following code to the project's `project.clj` file: -With Leiningen 1.x, add `[lein-marginalia "0.9.1"]` to your project.clj's `:dev-dependencies` argument of the `defproject` function, then run `lein deps`. -With Leiningen 2.x, add `[[lein-marginalia "0.9.1"]]` to the `:plugins` entry in either your project.clj file or your `:user` profile. +With Leiningen 1.x, add `[lein-marginalia "0.9.2"]` to your project.clj's `:dev-dependencies` argument of the `defproject` function, then run `lein deps`. +With Leiningen 2.x, add `[[lein-marginalia "0.9.2"]]` to the `:plugins` entry in either your project.clj file or your `:user` profile. See the [lein-marginalia](https://github.com/clj-commons/lein-marginalia) page for more details. Once installed, you can generate your complete source documentation with the command: @@ -132,6 +132,6 @@ If I've missed your name then please ping me. License ------- -Copyright (C) 2010-2017 Gary, Fogus and contributors. +Copyright (C) 2010-2024 Sean Corfield, Gary Deer, Fogus and contributors. Distributed under the Eclipse Public License, the same as Clojure. diff --git a/docs/uberdoc.html b/docs/uberdoc.html deleted file mode 100644 index abe11e21..00000000 --- a/docs/uberdoc.html +++ /dev/null @@ -1,3811 +0,0 @@ - -
dependencies
| (this space intentionally left almost blank) | ||||||||||||||||||
- | (ns leiningen.marg) | ||||||||||||||||||
Support eval-in-project in both Leiningen 1.x and 2.x. - | (defn eval-in-project - [project form init] - (let [[eip two?] (or (try (require 'leiningen.core.eval) - [(resolve 'leiningen.core.eval/eval-in-project) - true] - (catch java.io.FileNotFoundException _)) - (try (require 'leiningen.compile) - [(resolve 'leiningen.compile/eval-in-project)] - (catch java.io.FileNotFoundException _)))] - (if two? - (eip project form init) - (eip project form nil nil init)))) | ||||||||||||||||||
- | (def dep ['marginalia "0.9.1"]) | ||||||||||||||||||
- | (defn- add-marg-dep [project] - ;; Leiningen 2 is a bit smarter about only conjing it in if it - ;; doesn't already exist and warning the user. - (if-let [conj-dependency (resolve 'leiningen.core.project/conj-dependency)] - (conj-dependency project dep) - (update-in project [:dependencies] conj dep))) | ||||||||||||||||||
Note:- -The docstring for the marg function is used by Leiningen when a
-user types | |||||||||||||||||||
Run Marginalia against your project source files. - -Usage: - -
-
-Marginalia accepts options as described below: - --d --dir Directory into which the documentation will be written (default -f --file File into which the documentation will be written (default -n --name Project name (Taken from -v --version Project version (Taken from -D --desc Project description (Taken from -a --deps Project dependencies in the form -c --css Additional css resources -j --js Additional javascript resources -m --multi Generate each namespace documentation as a separate file - | (defn marg - [project & args] - (eval-in-project (add-marg-dep project) - `(binding [marginalia.html/*resources* ""] - (marginalia.core/run-marginalia (list ~@args))) - '(require 'marginalia.core))) | ||||||||||||||||||
A new way to think about programs- -What if your code and its documentation were one and the same? - -Much of the philosophy guiding literate programming is the realization of the answer to this question. -However, if literate programming stands as a comprehensive programming methodology at one of end of the -spectrum and no documentation stands as its antithesis, then Marginalia falls somewhere between. That is, -you should always aim for comprehensive documentation, but the shortest path to a useful subset is the -commented source code itself. - -The art of Marginalia- -If you’re fervently writing code that is heavily documented, then using Marginalia for your Clojure projects -is as simple as running it on your codebase. However, if you’re unaccustomed to documenting your source, then -the guidelines herein will help you make the most out of Marginalia for true-power documentation. - -Following the guidelines will work to make your code not only easier to follow: it will make it better. -The very process of using Marginalia will help to crystallize your understanding of problem and its solution(s). - -The quality of the prose in your documentation will often reflect the quality of the code itself thus highlighting -problem areas. The elimination of problem areas will solidify your code and its accompanying prose. Marginalia -provides a virtuous circle spiraling inward toward maximal code quality. - -The one true way- -
| (ns marginalia.core - (:require - [clojure.java.io :as io] - [clojure.string :as str] - [clojure.tools.cli :refer [cli]] - [marginalia.html :refer [uberdoc-html index-html single-page-html]] - [marginalia.parser :refer [parse-file parse-ns *lift-inline-comments* *delete-lifted-comments*]]) - (:import - (java.io File FileReader))) | ||||||||||||||||||
- | (set! *warn-on-reflection* true) | ||||||||||||||||||
File System Utilities- | |||||||||||||||||||
Performs roughly the same task as the UNIX | (defn ls - [path] - (let [file (io/file path)] - (if (.isDirectory file) - (seq (.list file)) - (when (.exists file) - [path])))) | ||||||||||||||||||
- | (defn mkdir [path] - (.mkdirs (io/file path))) | ||||||||||||||||||
Ensure that the directory specified by | (defn ensure-directory! - [path] - (when-not (ls path) - (mkdir path))) | ||||||||||||||||||
Many Marginalia fns use dir? to recursively search a filepath. - | (defn dir? - [path] - (.isDirectory (io/file path))) | ||||||||||||||||||
Returns a string containing the files extension. - | (defn find-file-extension - [^File file] - (second (re-find #"\.([^.]+)$" (.getName file)))) | ||||||||||||||||||
Predicate. Returns true for "normal" files with a file extension which -passes the provided predicate. - | (defn processable-file? - [pred ^File file] - (when (.isFile file) - (-> file find-file-extension pred))) | ||||||||||||||||||
Returns a seq of processable file paths (strings) in alphabetical order by -namespace. - | (defn find-processable-file-paths - [dir pred] - (->> (io/file dir) - (file-seq) - (filter (partial processable-file? pred)) - (sort-by parse-ns) - (map #(.getCanonicalPath ^File %)))) | ||||||||||||||||||
Project Info Parsing- -Marginalia will parse info out of your project.clj to display in -the generated html file's header. - | |||||||||||||||||||
Parses a project.clj file and returns a map in the following form - -
-
-by merging into the name and version information the rest of the defproject
-forms ( | (defn parse-project-form - [[_ project-name version-number & attributes]] - (merge {:name (str project-name) - :version version-number} - (apply hash-map attributes))) | ||||||||||||||||||
Parses a project file -- './project.clj' by default -- and returns a map - assembled according to the logic in parse-project-form. - | (defn parse-project-file - ([] (parse-project-file "./project.clj")) - ([path] - (try - (let [rdr (clojure.lang.LineNumberingPushbackReader. - (FileReader. - (io/file path)))] - (loop [line (read rdr)] - (let [found-project? (= 'defproject (first line))] - (if found-project? - (parse-project-form line) - (recur (read rdr)))))) - (catch Exception e - (throw (Exception. - (str - "There was a problem reading the project definition from " - path))))))) | ||||||||||||||||||
Source File Analysis- | |||||||||||||||||||
TODO: why are these args unused? - | (defn end-of-block? [_cur-group _groups lines] - (let [line (first lines) - next-line (second lines) - next-line-code (get next-line :code-text )] - (when (or (and (:code-text line) - (:docs-text next-line)) - (re-find #"^\(def" (str/trim next-line-code))) - true))) | ||||||||||||||||||
- | (defn merge-line [line m] - (cond - (:docstring-text line) (assoc m - :docs - (conj (get m :docs []) line)) - (:code-text line) (assoc m - :codes - (conj (get m :codes []) line)) - (:docs-text line) (assoc m - :docs - (conj (get m :docs []) line)))) | ||||||||||||||||||
- | (defn group-lines [doc-lines] - (loop [cur-group {} - groups [] - lines doc-lines] - (cond - (empty? lines) (conj groups cur-group) - (end-of-block? cur-group groups lines) - (recur (merge-line (first lines) {}) (conj groups cur-group) (rest lines)) - :else (recur (merge-line (first lines) cur-group) groups (rest lines))))) | ||||||||||||||||||
- | (defn path-to-doc [filename] - {:ns (parse-ns (io/file filename)) - :groups (parse-file filename)}) | ||||||||||||||||||
Output Generation- | |||||||||||||||||||
- | (defn filename-contents - [props output-dir all-files parsed-file] - {:name (io/file output-dir (str (:ns parsed-file) ".html")) - :contents (single-page-html props parsed-file all-files)}) | ||||||||||||||||||
- | (defn multidoc! - [output-dir files-to-analyze props] - (let [parsed-files (map path-to-doc files-to-analyze) - index (index-html props parsed-files) - pages (map #(filename-contents props output-dir parsed-files %) parsed-files)] - (doseq [f (conj pages {:name (io/file output-dir "toc.html") - :contents index})] - (spit (:name f) (:contents f))))) | ||||||||||||||||||
Generates an uberdoc html file from 3 pieces of information: - -
| (defn uberdoc! - [output-file-name files-to-analyze props] - (let [source (uberdoc-html - props - (map path-to-doc files-to-analyze))] - (spit output-file-name source))) | ||||||||||||||||||
External Interface (command-line, lein, cake, etc)- | |||||||||||||||||||
These functions support Marginalia's use by client software or command-line -users. - | |||||||||||||||||||
- | (def ^:private file-extensions #{"clj" "cljs" "cljx" "cljc"}) | ||||||||||||||||||
Given a collection of filepaths, returns a lazy sequence of filepaths to all - .clj, .cljs, .cljx, and .cljc files on those paths: directory paths will be searched - recursively for files. - | (defn format-sources - [sources] - (if (nil? sources) - (find-processable-file-paths "./src" file-extensions) - (->> sources - (mapcat #(if (dir? %) - (find-processable-file-paths % file-extensions) - [(.getCanonicalPath (io/file %))]))))) | ||||||||||||||||||
- | (defn split-deps [deps] - (when deps - (for [d (str/split deps #";") - :let [[group artifact version] (str/split d #":")]] - [(if (= group artifact) artifact (str group "/" artifact)) - version]))) | ||||||||||||||||||
Check if a source file is excluded from the generated documentation - | (defn source-excluded? - [source opts] - (if-not (empty? - (filter #(if (re-find (re-pattern %) source) - true - false) - (-> opts :marginalia :exclude))) - true - false)) | ||||||||||||||||||
Default generation: given a collection of filepaths in a project, find the .clj - files at these paths and, if Clojure source files are found: - -
| (defn run-marginalia - [args & [project]] - (let [[{:keys [dir file name version desc deps css js multi - leiningen exclude - lift-inline-comments exclude-lifted-comments]} files help] - (cli args - ["-d" "--dir" - "Directory into which the documentation will be written" :default "./docs"] - ["-f" "--file" - "File into which the documentation will be written" :default "uberdoc.html"] - ["-n" "--name" - "Project name - if not given will be taken from project.clj"] - ["-v" "--version" - "Project version - if not given will be taken from project.clj"] - ["-D" "--desc" - "Project description - if not given will be taken from project.clj"] - ["-a" "--deps" - "Project dependencies in the form <group1>:<artifact1>:<version1>;<group2>... - If not given will be taken from project.clj"] - ["-c" "--css" - "Additional css resources <resource1>;<resource2>;... - If not given will be taken from project.clj."] - ["-j" "--js" - "Additional javascript resources <resource1>;<resource2>;... - If not given will be taken from project.clj"] - ["-m" "--multi" - "Generate each namespace documentation as a separate file" :flag true] - ["-l" "--leiningen" - "Generate the documentation for a Leiningen project file."] - ["-e" "--exclude" - "Exclude source file(s) from the document generation process <file1>;<file2>;... - If not given will be taken from project.clj"] - ["-L" "--lift-inline-comments" - "Lift ;; inline comments to the top of the enclosing form. - They will be treated as if they preceded the enclosing form." :flag true] - ["-X" "--exclude-lifted-comments" - "If ;; inline comments are being lifted into documentation - then also exclude them from the source code display." :flag true]) - sources (distinct (format-sources (seq files))) - sources (if leiningen (cons leiningen sources) sources)] - (if-not sources - (do - (println "Wrong number of arguments passed to Marginalia.") - (println help)) - (binding [*lift-inline-comments* lift-inline-comments - *delete-lifted-comments* exclude-lifted-comments] - (let [project-clj (or project - (when (.exists (io/file "project.clj")) - (parse-project-file))) - choose #(or %1 %2) - marg-opts (merge-with choose - {:css (when css (str/split css #";")) - :javascript (when js (str/split js #";")) - :exclude (when exclude (str/split exclude #";")) - :leiningen leiningen} - (:marginalia project-clj)) - opts (merge-with choose - {:name name - :version version - :description desc - :dependencies (split-deps deps) - :multi multi - :marginalia marg-opts} - project-clj) - sources (->> sources - (filter #(not (source-excluded? % opts))) - (into []))] - (println "Generating Marginalia documentation for the following source files:") - (doseq [s sources] - (println " " s)) - (println) - (ensure-directory! dir) - (if multi - (multidoc! dir sources opts) - (uberdoc! (str dir "/" file) sources opts)) - (println "Done generating your documentation in" dir) - (println "")))))) | ||||||||||||||||||
Utilities for converting parse results into html. - | (ns marginalia.html - (:use [marginalia.hiccup :only (html escape-html)]) - (:require [clojure.string :as str]) - (:import [com.petebevin.markdown MarkdownProcessor])) | ||||||||||||||||||
- | (def ^{:dynamic true} *resources* "./vendor/") | ||||||||||||||||||
- | (defn css-rule [rule] - (let [sels (reverse (rest (reverse rule))) - props (last rule)] - (str (apply str (interpose " " (map name sels))) - "{" (apply str (map #(str (name (key %)) ":" (val %) ";") props)) "}"))) | ||||||||||||||||||
Quick and dirty dsl for inline css rules, similar to hiccup. - - ex. -> | (defn css - [& rules] - (html [:style {:type "text/css"} - (apply str (map css-rule rules))])) | ||||||||||||||||||
Stolen from leiningen - | (defn slurp-resource - [resource-name] - (try - (-> (.getContextClassLoader (Thread/currentThread)) - (.getResourceAsStream resource-name) - (java.io.InputStreamReader.) - (slurp)) - (catch java.lang.NullPointerException npe - (println (str "Could not locate resources at " resource-name)) - (println " ... attempting to fix.") - (let [resource-name (str *resources* resource-name)] - (try - (-> (.getContextClassLoader (Thread/currentThread)) - (.getResourceAsStream resource-name) - (java.io.InputStreamReader.) - (slurp)) - (catch java.lang.NullPointerException npe - (println (str " STILL could not locate resources at " resource-name ". Giving up!")))))))) | ||||||||||||||||||
- | (defn inline-js [resource] - (let [src (slurp-resource resource)] - (html [:script {:type "text/javascript"} - src]))) | ||||||||||||||||||
- | (defn inline-css [resource] - (let [src (slurp-resource resource)] - (html [:style {:type "text/css"} - (slurp-resource resource)]))) | ||||||||||||||||||
The following functions handle preparation of doc text (both comment and docstring -based) for display through html & css. - | |||||||||||||||||||
Markdown processor. - | (def mdp (com.petebevin.markdown.MarkdownProcessor.)) | ||||||||||||||||||
Markdown string to html converter. Translates strings like: - - "# header!" -> "## header!" -> ... - | (defn md - [s] - (.markdown mdp s)) | ||||||||||||||||||
As a result of docifying then grouping, you'll end up with a seq like this one: - -
-
-
| |||||||||||||||||||
Converts a docs section to html by threading each doc line through the forms - outlined above. - -ex. (docs-to-html [{:doc-text "# hello world!"} {:docstring-text "I'm a docstring!}]) - - -> | (defn docs-to-html - [docs] - (-> docs - str - (md))) | ||||||||||||||||||
- | (defn codes-to-html [code-block] - (html [:pre {:class "brush: clojure"} - (escape-html code-block)])) | ||||||||||||||||||
- | (defn section-to-html [section] - (html [:tr - [:td {:class "docs"} (docs-to-html - (if (= (:type section) :comment) - (:raw section) - (:docstring section)))] - [:td {:class "codes"} (if (= (:type section) :code) - (codes-to-html (:raw section)))]])) | ||||||||||||||||||
- | (defn dependencies-html [deps & header-name] - (when-let [deps (seq deps)] - (let [header-name (or header-name "dependencies")] - (html [:div {:class "dependencies"} - [:h3 header-name] - [:table - (map #(html [:tr - [:td {:class "dep-name"} (str (first %))] - [:td {:class "dotted"} [:hr]] - [:td {:class "dep-version"} (second %)]]) - deps)]])))) | ||||||||||||||||||
Load Optional Resources- -Use external Javascript and CSS in your documentation. For example: -To format Latex math equations, download the -MathJax Javascript library to the docs -directory and then add - -
-
-to project.clj. Below is a simple example of both inline and block -formatted equations. - -Optionally, you can put the MathJax CDN URL directly as a value of
-
-That way you won't have to download and carry around the MathJax library. - -When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\) and they are -$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$ - | |||||||||||||||||||
Generate script and link tags for optional external javascript and css. - | (defn opt-resources-html - [project-info] - (let [options (:marginalia project-info) - javascript (:javascript options) - css (:css options)] - (html (concat - (when javascript - (map #(vector :script {:type "text/javascript" :src %}) javascript)) - (when css - (map #(vector :link {:tyle "text/css" :rel "stylesheet" :href %}) css)))))) | ||||||||||||||||||
Is <h1/> overloaded? Maybe we should consider redistributing -header numbers instead of adding classes to all the h1 tags. - | (defn header-html [project-info] - (html - [:tr - [:td {:class "docs"} - [:div {:class "header"} - [:h1 {:class "project-name"} (if (seq (:url project-info)) - [:a {:href (:url project-info)} (:name project-info)] - (:name project-info))] - [:h2 {:class "project-version"} (:version project-info)] - [:br] - (md (:description project-info))] - (dependencies-html (:dependencies project-info)) - (dependencies-html (:dev-dependencies project-info) "dev dependencies")] - [:td {:class "codes" - :style "text-align: center; vertical-align: middle;color: #666;padding-right:20px"} - [:br] - [:br] - [:br] - "(this space intentionally left almost blank)"]])) | ||||||||||||||||||
Creates an 'a' tag pointing to the | (defn link-to-namespace - [namespace-name anchor? & attrs] - [:a (into {:href (if anchor? - (str "#" namespace-name) - (str namespace-name ".html"))} - attrs) - namespace-name]) | ||||||||||||||||||
This is a hack, as in the case when | (defn link-to-toc - [anchor?] - (link-to-namespace "toc" anchor? {:class "toc-link"})) | ||||||||||||||||||
- | (defn toc-html [props docs] - (html - [:tr - [:td {:class "docs"} - [:div {:class "toc"} - [:a {:name "toc"} [:h3 "namespaces"]] - [:ul - (map #(vector :li (link-to-namespace (:ns %) (:uberdoc? props))) - docs)]]] - [:td {:class "codes"} " "]])) | ||||||||||||||||||
- | (defn floating-toc-html [docs] - [:div {:id "floating-toc"} - [:ul - (map #(vector :li {:class "floating-toc-li" - :id (str "floating-toc_" (:ns %))} - (:ns %)) - docs)]]) | ||||||||||||||||||
- | (defn groups-html [props doc] - (html - [:tr - [:td {:class "docs"} - [:div {:class "docs-header"} - [:a {:class "anchor" :name (:ns doc) :href (str "#" (:ns doc))} - [:h1 {:class "project-name"} - (:ns doc)] - (link-to-toc (:uberdoc? props))]]] - [:td {:class "codes"}]] - (map section-to-html (:groups doc)) - [:tr - [:td {:class "spacer docs"} " "] - [:td {:class "codes"}]])) | ||||||||||||||||||
- | (def reset-css - (css [:html {:margin 0 :padding 0}] - [:h1 {:margin 0 :padding 0}] - [:h2 {:margin 0 :padding 0}] - [:h3 {:margin 0 :padding 0}] - [:h4 {:margin 0 :padding 0}] - [:a {:color "#261A3B"}] - [:a:visited {:color "#261A3B"}])) | ||||||||||||||||||
- | (def header-css - (css [:.header {:margin-top "30px"}] - [:h1.project-name {:font-size "34px" - :display "inline"}] - [:h2.project-version {:font-size "18px" - :margin-top 0 - :display "inline" - :margin-left "10px"}] - [:.toc-link {:font-size "12px" - :margin-left "10px" - :color "#252519" - :text-decoration "none"}] - [:.toc-link:hover {:color "#5050A6"}] - [:.toc :h1 {:font-size "34px" - :margin 0}] - [:.docs-header {:border-bottom "dotted #aaa 1px" - :padding-bottom "10px" - :margin-bottom "25px"}] - [:.toc :h1 {:font-size "24px"}] - [:.toc {:border-bottom "solid #bbb 1px" - :margin-bottom "40px"}] - [:.toc :ul {:margin-left "20px" - :padding-left "0px" - :padding-top 0 - :margin-top 0}] - [:.toc :li {:list-style-type "none" - :padding-left 0}] - [:.dependencies {}] - [:.dependencies :table {:font-size "16px" - :width "99.99%" - :border "none" - :margin-left "20px"}] - [:.dependencies :td {:padding-right "20px;" - :white-space "nowrap"}] - [:.dependencies :.dotted {:width "99%"}] - [:.dependencies :.dotted :hr {:height 0 - :noshade "noshade" - :color "transparent" - :background-color "transparent" - :border-bottom "dotted #bbb 1px" - :border-top "none" - :border-left "none" - :border-right "none" - :margin-bottom "-6px"}] - [:.dependencies :.dep-version {:text-align "right"}] - [:.plugins :ul {:margin-left "20px" - :padding-left "0px" - :padding-top 0 - :margin-top 0}] - [:.plugins :li {:list-style-type "none" - :padding-left 0}] - [:.header :p {:margin-left "20px"}])) | ||||||||||||||||||
- | (def floating-toc-css - (css [:#floating-toc {:position "fixed" - :top "10px" - :right "20px" - :height "20px" - :overflow "hidden" - :text-align "right"}] - [:#floating-toc :li {:list-style-type "none" - :margin 0 - :padding 0}])) | ||||||||||||||||||
- | (def general-css - (css - [:body {:margin 0 - :padding 0 - :font-family "'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;" - :font-size "16px" - :color "#252519" - :background-color "#F5F5FF"}] - [:h1 {:font-size "20px" - :margin-top 0}] - [:h2 {:font-size "18px"}] - [:h3 {:font-size "16px"}] - [:a.anchor {:text-decoration "none" - :color "#252519"}] - [:a.anchor:hover {:color "#5050A6"}] - [:table {:border-spacing 0 - :border-bottom "solid #ddd 1px;" - :margin-bottom "10px"}] - [:code {:display "inline"}] - [:p {:margin-top "8px"}] - [:tr {:margin "0px" - :padding "0px"}] - [:td.docs {:width "410px" - :max-width "410px" - :vertical-align "top" - :margin "0px" - :padding-left "55px" - :padding-right "20px" - :border "none" - :background-color "#FFF"}] - [:td.docs :pre {:font-size "12px" - :overflow "hidden"}] - [:td.codes {:width "55%" - :background-color "#F5F5FF" - :vertical-align "top" - :margin "0px" - :padding-left "20px" - :border "none" - :overflow "hidden" - :font-size "10pt" - :border-left "solid #E5E5EE 1px"}] - [:td.spacer {:padding-bottom "40px"}] - [:pre :code {:display "block" - :padding "4px"}] - [:code {:background-color "ghostWhite" - :border "solid #DEDEDE 1px" - :padding-left "3px" - :padding-right "3px" - :font-size "14px"}] - [:.syntaxhighlighter :code {:font-size "13px"}] - [:.footer {:text-align "center"}])) | ||||||||||||||||||
Notice that we're inlining the css & javascript for SyntaxHighlighter ( | (defn page-template - [project-metadata opt-resources header toc content floating-toc] - (html - "<!DOCTYPE html>\n" - [:html - [:head - [:meta {:http-equiv "Content-Type" :content "text/html" :charset "utf-8"}] - [:meta {:name "description" :content (:description project-metadata)}] - (inline-css (str *resources* "shCore.css")) - (css - [:.syntaxhighlighter {:overflow "hidden !important"}]) - (inline-css (str *resources* "shThemeMarginalia.css")) - reset-css - header-css - floating-toc-css - general-css - (inline-js (str *resources* "jquery-1.7.1.min.js")) - (inline-js (str *resources* "xregexp-min.js")) - (inline-js (str *resources* "shCore.js")) - (inline-js (str *resources* "shBrushClojure.js")) - opt-resources - [:title (:name project-metadata) " -- Marginalia"]] - [:body - [:table - header - toc - content] - [:div {:class "footer"} - "Generated by " - [:a {:href "https://github.com/clj-commons/marginalia"} "Marginalia"] - ". " - "Syntax highlighting provided by Alex Gorbatchev's " - [:a {:href "http://alexgorbatchev.com/SyntaxHighlighter/"} - "SyntaxHighlighter"] - floating-toc] - (inline-js (str *resources* "app.js"))]])) | ||||||||||||||||||
Syntax highlighting is done a bit differently than docco. Instead of embedding -the highlighting metadata on the parse / html gen phase, we use SyntaxHighlighter -to do it in javascript. - | |||||||||||||||||||
This generates a stand alone html file (think | (defn uberdoc-html - [project-metadata docs] - (page-template - project-metadata - (opt-resources-html project-metadata) - (header-html project-metadata) - (toc-html {:uberdoc? true} docs) - (map #(groups-html {:uberdoc? true} %) docs) - (floating-toc-html docs))) | ||||||||||||||||||
- | (defn index-html - [project-metadata docs] - (page-template - project-metadata - (opt-resources-html project-metadata) - (header-html project-metadata) - (toc-html {:uberdoc? false} docs) - ;; no contents)) ;; no floating toc | ||||||||||||||||||
no floating toc - | |||||||||||||||||||
- | (defn single-page-html - [project-metadata doc all-docs] - (page-template - project-metadata - (opt-resources-html project-metadata) - ;; no header - ;; no toc - (groups-html {:uberdoc? false} doc) - ;; no floating toc)) | ||||||||||||||||||
A place to examine poor parser behavior. These should go in tests when they get written. - | (ns problem-cases.general) | ||||||||||||||||||
- | [::foo] | ||||||||||||||||||
- | {:foo 43} -{::foo 42} | ||||||||||||||||||
private docstring - | (defn ^:private private-fn []) | ||||||||||||||||||
docstring - | (defn public-fn [] - (let [x (private-fn)] - (count x))) | ||||||||||||||||||
Should have only this comment in the left margin. -See https://github.com/clj-commons/marginalia/issues/4 - | |||||||||||||||||||
- | (defn parse-bool [v] (condp = (.trim (str v)) - "0" false - "1" true - "throw exception here")) | ||||||||||||||||||
Here is a docstring. It should be to the left. - | (defn a-function - [x] - (* x x)) | ||||||||||||||||||
Here is a docstring. It should be to the left. - | (defn b-function - [x] - "Here is just a string. It should be to the right." - (* x x)) | ||||||||||||||||||
Defines a relation... duh! - | (defprotocol Relation - (select [this predicate] - "Confines the query to rows for which the predicate is true - Ex. (select (table :users) (where (= :id 5)))") - (join [this table2 join_on] - "Joins two tables on join_on - Ex. (join (table :one) (table :two) :id) - (join (table :one) (table :two) - (where (= :one.col :two.col)))")) | ||||||||||||||||||
This is a defmulti docstring, it should also be on the left - | (defmulti bazfoo - class) | ||||||||||||||||||
- | (defmethod bazfoo String [s] - "This is a defmethod docstring. It should be on the left." - (vec (seq s))) | ||||||||||||||||||
- | (bazfoo "abc") | ||||||||||||||||||
This is a protocol docstring. It should be on the left. - | (defprotocol Foo - (lookup [cache e]) - (has? [cache e] ) - (hit [cache e]) - (miss [cache e ret])) | ||||||||||||||||||
This is also a docstring via metadata. It should be on the left. - | (def - a 42) | ||||||||||||||||||
This is also a docstring via metadata. It should be on the left. - | (def - b 42) | ||||||||||||||||||
This is also a docstring via metadata. It should be on the left. - | (def - c - "This is just a value. It should be on the right.") | ||||||||||||||||||
From fnparse - | |||||||||||||||||||
Padded on the front with optional whitespace. - | (comment - (do-template [rule-name token] - (h/defrule rule-name - (h/lit token)) - <escape-char-start> \\ - <str-delimiter> \" - <value-separator> \, - <name-separator> \: - <array-start> \[ - <array-end> \] - <object-start> \{ - <object-end> \})) | ||||||||||||||||||
Issue #26: Angle-bracket in Function Name Breaks Layout - | (defn <test [] nil) | ||||||||||||||||||
(defn test-html-entities-in-doc - [] - nil) | |||||||||||||||||||
- | (defmulti kompile identity) | ||||||||||||||||||
- | (defmethod kompile [:standard] - [_] - "GENERATED ALWAYS AS IDENTITY") | ||||||||||||||||||
Resulting expressions are wrapped in an anonymous function and, down the line,
- | (defn strict-eval-op-fn - [op inc-ind-str ind-str op nl] - (ind-str - "(function() {" nl - (inc-ind-str - "var _out = arguments[0];" nl - "for(var _i=1; _i<arguments.length; _i++) {" nl - (inc-ind-str - "_out = _out " op " arguments[_i];") - nl - "}" nl - "return _out;") - nl - "})")) | ||||||||||||||||||
- | '(defn special-forms [] - {'def handle-def - 'fn handle-fn - 'fn* handle-fn - 'set! handle-set - 'let handle-let - 'defn handle-defn - 'aget handle-aget - 'aset handle-aset - 'if handle-if - 'while handle-while - 'when handle-when - 'doto handle-doto - '-> handle--> - '->> handle-->> - 'not handle-not - 'do handle-do - 'cond handle-cond - '= (make-lazy-op '==) - '> (make-lazy-op '>) - '< (make-lazy-op '<) - '>= (make-lazy-op '>=) - '<= (make-lazy-op '<=) - 'or (make-lazy-op '||) - 'and (make-lazy-op '&&) - 'doseq handle-doseq - 'instanceof handle-instanceof - 'gensym handle-gensym - 'gensym-str handle-gensym-str}) | ||||||||||||||||||
- | '(defn greater [a b] - (>= a b)) | ||||||||||||||||||
- | '(fact - (greater 2 1) => truthy) | ||||||||||||||||||
- | '(file->tickets commits) | ||||||||||||||||||
- | (defmulti ns-kw-mm identity) -(defmethod ns-kw-mm ::foo [_] :problem-cases.general/foo) -(defmethod ns-kw-mm :user/foo [_] :user/foo) -(defmethod ns-kw-mm :foo [_] :foo) | ||||||||||||||||||