Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{:linters {:shadowed-var {:level :warning}
:single-key-in {:level :warning}
:missing-docstring {:level :warning}}
:missing-docstring {:level :ignore}}
:lint-as {;; Herb
herb.core/defglobal clojure.core/def

Expand Down
6 changes: 5 additions & 1 deletion .dir-locals.el
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
((nil . ((cider-clojure-cli-aliases . ":dev:behave/app")
(cider-default-cljs-repl . figwheel-main))))
(cider-default-cljs-repl . figwheel-main)
(eval . (progn
(load (expand-file-name "scripts/behave.el"
(locate-dominating-file buffer-file-name ".dir-locals.el")))
(add-hook 'after-save-hook #'behave-format-on-save nil t))))))

;; VMS Configuration
;; TODO: Fix to avoid having two separate aliases for projects
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/clj-kondo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: clj-kondo linter

on:
pull_request:
branches:
- main

jobs:
clj-lint:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Get changed Clojure files
id: changed-files
run: |
FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.(clj|cljs|cljc)$' | tr '\n' ' ')
echo "files=$FILES" >> $GITHUB_OUTPUT
echo "has_files=$([ -n "$FILES" ] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT

- uses: DeLaGuardo/clojure-lint-action@master
if: steps.changed-files.outputs.has_files == 'true'
with:
clj-kondo-args: --lint ${{ steps.changed-files.outputs.files }}
github_token: ${{ secrets.GITHUB_TOKEN }}
74 changes: 74 additions & 0 deletions scripts/align_requires.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bb
(ns align-requires
(:require [babashka.fs :as fs]
[clojure.string :as str]
[rewrite-clj.zip :as z]
[rewrite-clj.node :as n]))

(defn- keyword-entry?
"True if a require vector has :as or :refer as its second element.
Uses z/right (skips whitespace) to find the keyword directly."
[zloc]
(when-let [second-child (-> zloc z/down z/right)]
(try (#{:as :refer} (z/sexpr second-child))
(catch Exception _ nil))))

(defn- require-vectors
"Returns all zipper locations of [ns-sym :as/:refer ...] vectors
within the :require clause of the given file zipper."
[root-zloc]
(->> root-zloc
(iterate z/next)
(take-while (complement z/end?))
(filter #(and (z/vector? %) (keyword-entry? %)))))

(defn- ns-sym-len
[entry-zloc]
(count (str (z/sexpr (z/down entry-zloc)))))

(defn- set-whitespace-after-ns-sym
[entry-zloc spaces]
(let [ws-node (n/whitespace-node (str/join (repeat spaces " ")))]
(-> entry-zloc
z/down ; at ns-sym
z/right* ; at raw whitespace node between ns-sym and keyword
(z/replace ws-node)
z/up)))

(defn- align-file!
"Aligns all `:imports`/`:requires` dependencies."
[path]
(let [content (slurp path)
zloc (z/of-string content {:track-position? true})
entries (require-vectors zloc)]
(when (seq entries)
(let [max-len (apply max (map ns-sym-len entries))
;; Re-parse to get fresh zipper for mutations
aligned (loop [acc (z/of-string content)]
(let [es (require-vectors acc)
;; Find first entry whose spacing doesn't match target
target (fn [e] (- (inc max-len) (ns-sym-len e)))
bad-e (first (filter (fn [e]
(let [ws (-> e z/down z/right*)]
(not= (str/join (repeat (target e) " "))
(z/string ws))))
es))]
(if bad-e
(recur (set-whitespace-after-ns-sym bad-e (target bad-e)))
acc)))
new-content (z/root-string aligned)]
(when (not= content new-content)
(println "Aligned:" path)
(spit path new-content))))))

(let [arg (or (first *command-line-args*) ".")
paths (if (fs/regular-file? arg)
[arg]
(->> (fs/glob arg "**/*.{clj,cljs,cljc}")
(map str)
(remove #(re-find #"/(target|node_modules|resources/public/cljs)/" %))))]
(doseq [path paths]
(align-file! path)))

;; usage
;; bb align_requires.clj <file>
32 changes: 32 additions & 0 deletions scripts/behave.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
;;; behave.el --- Project-local Emacs helpers for behave-polylith

(defun behave-format-on-save ()
"Run cljfmt fix + align_requires on save, then silently revert buffer."
(let* ((project-root (locate-dominating-file buffer-file-name ".dir-locals.el"))
(align-script (expand-file-name "scripts/align_requires.clj" project-root))
(file (buffer-file-name))
(buf (current-buffer))
(cmd (format "cd %s && bb %s %s && clojure -M:format fix %s"
(shell-quote-argument project-root)
(shell-quote-argument align-script)
(shell-quote-argument file)
(shell-quote-argument file))))
(make-process
:name "clj-format-on-save"
:buffer nil
:command (list "bash" "-c" cmd)
:sentinel (lambda (_proc event)
(when (and (string-prefix-p "finished" event)
(buffer-live-p buf))
(with-current-buffer buf
(unless (buffer-modified-p)
(revert-buffer t t t))))))))

(defun behave-jack-in-cms ()
"Start the VMS/CMS REPL via `cider-jack-in-clj&cljs` with the :dev:behave/cms alias."
(interactive)
(let ((cider-clojure-cli-aliases ":dev:behave/cms"))
(cider-jack-in-clj&cljs nil)))

(provide 'behave)
;;; behave.el ends here