Skip to content

Instantly share code, notes, and snippets.

@jdevera
Created February 20, 2023 09:52
Show Gist options
  • Save jdevera/4a708abe505cb008478e69d1f35c90b7 to your computer and use it in GitHub Desktop.
Save jdevera/4a708abe505cb008478e69d1f35c90b7 to your computer and use it in GitHub Desktop.
Namespaces Catalog for Roam Research (v.1.0)
(ns namespaces-catalog-v1.0
(:require [roam.datascript :as rd]
[roam.util :refer [parse]]))
(def SEP "/")
(defn namespaced-pages
" Get all pages in the graph that have a namespace (they contain / in the title)"
[]
(map first
(rd/q '[:find ?fulltitle
:where [?e :node/title ?fulltitle]
[(clojure.string/includes? ?fulltitle "/")]])))
(defn page-exists?
"Checks whether a given page title exists in the graph"
[page]
(not (nil? (first (rd/q '[:find ?fulltitle
:in $ ?page
:where [?p :node/title ?page]
[?p :node/title ?fulltitle]] page)))))
(defn page-link
"Linkify page title if it exists in the graph. Otherwise, return the title as is."
[name]
(if (page-exists? name)
(parse (str "[[" name "]]"))
name))
(defn expand
"Given a namespace path as a list of its parts, return a list of progressively
longer paths that ends with the given path.
Example: [a b c] -> [[] [a] [a b] [a b c]]"
[path-parts]
(->> path-parts
(reduce (fn [acc x] (conj acc (conj (last acc) x))) [[]])
(map #(clojure.string/join SEP %))))
(defn indent
"Given a vector starting with a path as a string, prepend the depth of the path
as the number of parts in it.
Example: [a/b/c _] -> [3 a/b/c _]"
[path]
(into [(count (clojure.string/split (first path) SEP))] path))
(defn count-pages-for-namespaces
"For a list of pages, give back a list of namespaces and the count of pages
in each. Note that it expands to all levels of namespaces. An indication of
the level of indentation is also returned: [indentation path page-count]
Example: [a/b/page d/page2] -> [[1 a 1] [2 a/b 1] [1 d 1]]"
[pages]
(->> pages
sort
(map #(clojure.string/split % SEP))
(map drop-last)
(map expand)
flatten
(remove empty?)
frequencies
sort
(map indent)))
(defn make-row
"Turn a vector of indentation, namespace and page-count into a table row for
presentation. The indentation value is used to style the namespace left padding."
[indentation path page-count]
[:tr
[:td {:style {:padding-left (str indentation "ex")}} (page-link path)]
[:td page-count]])
(defn make-table
"Create a table with the namespace results."
[rows]
(def HEADER [:tr [:th "Namespace"] [:th "Number of pages"]])
[:table
HEADER
(map #(apply make-row %) rows)
])
(defn main
[]
(make-table (count-pages-for-namespaces (namespaced-pages))))
@jdevera
Copy link
Author

jdevera commented Feb 20, 2023

Instructions to use:

  1. Create a code block with the language set to clojure somewhere in your Roam graph.
  2. Copy the block reference of said code block.
  3. Anywhere you want the catalogue to appear, use this as the content of your block {{roam/render: ((auxjxGG3h))}} (where auxjxGG3h is the block reference you got on step 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment