├── .clj-kondo └── config.edn ├── .github └── FUNDING.yml ├── .gitignore ├── README.md ├── calva └── config.edn ├── clojure-lsp └── config.edn ├── joyride ├── scripts │ ├── clojuredocs.cljs │ ├── example_repl.cljs │ ├── javadoc.cljs │ ├── ns.cljs │ └── tap.cljs └── src │ └── remote_repl.cljs ├── keybindings.json └── settings.json /.clj-kondo/config.edn: -------------------------------------------------------------------------------- 1 | {:lint-as 2 | {promesa.core/let clojure.core/let}} 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: seancorfield 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .calva/mcp-server/port 2 | .calva/repl.calva-repl 3 | .clj-kondo/.cache 4 | .lsp/.cache 5 | .portal/ 6 | globalStorage 7 | History 8 | sync 9 | workspaceStorage 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VS Code Setup 2 | 3 | The files here represent my current [VS Code](https://code.visualstudio.com/) 4 | configuration for use with 5 | [Calva](https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva), 6 | [Calva Power Tools](https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva-power-tools), 7 | [Joyride](https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.joyride), 8 | and [clojure-lsp](https://clojure-lsp.io/). 9 | 10 | > Note: Some of the code here may well assume you are using the latest version of Calva and Joyride -- I tend to update my extensions regularly and also update my configuration to take advantage of new features. Specifically, the Joyride code here depends on the `v1` API in Calva, 2.0.401 or later! 11 | 12 | * `keybindings.json` is my cross-platform key mappings (warning: I've customized Copilot and LiveShare key bindings, amongst others!), 13 | * `settings.json` is my user-level settings (consider this optional -- the `calva/config.edn` file with the `customREPLCommandSnippets` is the interesting part). 14 | 15 | ## Installation 16 | 17 | You can either clone this repo into a temporary directory and then copy either or both of `.json` files into your VS Code user configuration directory (overwriting the default `keybindings.json` and `settings.json` files), or you can manually update your files with whatever bits of my files you like. 18 | 19 | Copy (or merge) the `calva/config.edn` file's `customREPLCommandSnippets` into your 20 | `~/.config/calva/config.edn` file for VS Code to find them (requires Calva 2.0.307 or later!). 21 | These `customREPLCommandSnippets` provide a number of `tap>` evaluations and some [Portal UI](https://github.com/djblue/portal) commands. 22 | 23 | Copy (or merge) the `joyride/scripts/*` and `joyride/src/*` files into your 24 | `~/.config/joyride/` directories. 25 | 26 | Copy (or merge) the `clojure-lsp/config.edn` file into your 27 | `~/.config/clojure-lsp/config.edn` file. 28 | 29 | **Requires Portal 0.40.0 or later** 30 | 31 | In addition, there are some Joyride scripts (in `joyride/scripts`) that you can copy into either your user or workspace Joyride `scripts` folder as desired. See the **Joyride** section below for details. 32 | 33 | On a Mac, the VS Code user configuration directory is as shown below: 34 | 35 | ```bash 36 | $ cd ~/Library/Application\ Support/Code/User 37 | ``` 38 | 39 | On Windows, the VS Code user configuration directory is likely to be: 40 | 41 | ```bash 42 | > cd C:\Users\\AppData\Roaming\Code\User 43 | ``` 44 | 45 | ## Portal: Launch and Usage 46 | 47 | **Requires Portal 0.40.0 or later** 48 | 49 | Will work both with and without the `portal.nrepl/wrap-portal` middleware. 50 | 51 | The REPL snippet that launches Portal inside VS Code will launch **two** 52 | Portal windows: 53 | * one called `** logging **` which tracks all Portal middleware evaluations and, if you use my `:dev/repl` alias from my [`dot-clojure`](https://github.com/seancorfield/dot-clojure) repo, all `clojure.tools.logging` output 54 | * one named for the directory it is opened in which tracks all plain `tap>` calls 55 | 56 | ### Prerequisites 57 | 58 | When starting an instance of Portal, you must ensure that you have the following: 59 | 60 | Portal itself must be included as a dependency. This can be done in your user configuration file (`deps.edn` or `~/.lein/profiles.clj` for example) or in your project's configuration. If you're using Leiningen, it'll look like this: 61 | 62 | `:dependencies [[djblue/portal "RELEASE"]]` 63 | 64 | For `deps.edn`, it will be `djblue/portal {:mvn/version "RELEASE"}` in `:extra-deps` under an alias. If you're using my user `deps.edn` file from my [`dot-clojure`](https://github.com/seancorfield/dot-clojure) repo, you can just add the `:portal` alias to your CLI command to get the latest Portal included. 65 | 66 | > Note: On Windows/WSL2, you may need `localhostForwarding=true` added to the `[wsl2]` section of your `.wslconfig` file for the VS Code / Portal server connection to work correctly. 67 | 68 | ### Launching and Using Portal 69 | 70 | Before you launch Portal, you must first start a REPL and connect to it. Once that is up and connected in Calva, you can use the following custom REPL command: 71 | 72 | * `ctrl+alt+space p` -- launch Portal inside VS Code; this uses a custom `submit` listener for `tap>` that tracks middleware output + logging and regular `tap>` calls in separate atoms, one behind each of the two windows opened 73 | 74 | The following additional custom REPL commands are available for Portal, and they all operate on the regular result window (not the middleware output/logging window): 75 | 76 | * `ctrl+alt+space k` -- clear the Portal history 77 | * `ctrl+alt+space 0` -- cycle the latest value in the Portal history through each of the viewers in turn 78 | * `ctrl+alt+space 1` -- expand/collapse the first level of the most recent `tap>`'d value in Portal; `2`, `3`, `4`, and `5` affect the second thru fifth level respectively 79 | 80 | You can also access values stored in portal by dereferencing the `portal` object in the `dev` namespace like so: `@dev/portal`. This object is created automatically by the launch command snippet. 81 | 82 | Similarly, `(first @dev/my-taps)` is always the most recent value `tap>`'d and the following 83 | custom REPL command lets you manipulate it: 84 | 85 | * `ctrl+alt+space q` -- pops open a REPL input prompt into which you can type arbitrary code which will be evaluated and `tap>`'d 86 | 87 | If that code includes `*v`, it will be automatically replaced with `(first @dev/my-taps)` 88 | so you can use the following workflow: 89 | 90 | * `tap>` any value into Portal via any method 91 | * `ctrl+alt+space q` and type some expression involving `*v` 92 | * press enter to have that evaluated and `tap>`'d 93 | * rinse and repeat! 94 | 95 | See the custom REPL commands below for convenient `tap>` functionality. 96 | 97 | ## Custom REPL Command Snippets and `tap>` 98 | 99 | In addition to the custom REPL commands snippets mentioned above for Portal, 100 | this `settings.json` file includes the following: 101 | 102 | * `ctrl+alt+space c` -- run the current test (use `ctrl+alt+space o` to see output/report) and display a summary of results. 103 | * `ctrl+alt+space d` -- when a binding in `let` is highlighted (both the symbol and the expression to which it is bound), this creates a `def` so the symbol becomes available at the top level: useful for debugging parts of a function inside `let`. 104 | * `ctrl+alt+space e` -- `tap>` the last exception thrown (`*e`) 105 | * `ctrl+alt+space i` -- when a symbol is highlighted, create a `def` from it bound to an input value provided by a REPL prompt in Calva: useful for debugging parts of a function (by defining argument values or other symbols). 106 | * `ctrl+alt+space l` -- "lift" the result out of the most recent `** logging **` window entry into the regular `tap>` window for easier manipulation. 107 | * `ctrl+alt+space n` -- `tap>` a hash map of public Vars from the current namespace. 108 | * `ctrl+alt+space o` -- where `l` lifts the _result_ from `** logging **`, this lifts the standard output (and any test reports): useful when you want to see output produced by an evaluation or test results (from `ctrl+alt+space c` or `t` or `x`) 109 | * `ctrl+alt+space r` -- runs `com.mjdowney.rich-comment-tests/run-ns-tests!` on the current namespace to treat any `comment` forms annotated as `:rct/test` as actual tests; see https://github.com/matthewdowney/rich-comment-tests/ for more details. 110 | * `ctrl+alt+space t` -- run all the tests in the current namespace (use `ctrl+alt+space o` to see output/report) and display a summary of results. 111 | * `ctrl+alt+space x` -- run all the tests in the "associated" namespace (use `ctrl+alt+space o` to see output/report) and display a summary of results; if the current namespace is `foo.bar`, this will look for `foo.bar-test` or `foo.bar-expectations`. 112 | * `ctrl+alt+space z` -- zap (remove) the current namespace's definitions: occasionally useful for cleaning up REPL state; this unaliases/unmaps all the symbols in the namespace _without destroying the namespace itself_, leaving it "empty" so you can load the file from disk again so it is fully-sync'd (`ctrl+alt+c enter`). 113 | 114 | Several of these command snippets _require_ Clojure 1.10 or later (because they assume `requiring-resolve` and `tap>`) and will fail on earlier versions. Portal supports Clojure 1.10's `datafy` and `nav`. 115 | 116 | ## Joyride Scripts 117 | 118 | The following scripts perform tasks that my old Clover configuration used to provide. You'll need Joyride installed in VS Code and you'll need at least v2.0.277 of Calva since these scripts depend on the recently-added [Calva Extension API](https://calva.io/api/). 119 | 120 | * `clojuredocs.cljs` -- with a Clojure symbol selected, this will open VS Code's Simple Browser, directly inside VS Code, at the corresponding [ClojureDocs page](https://clojuredocs.org). 121 | * `javadoc.cljs` -- with a Java class name selected, or a Clojure expression selected, this will open VS Code's Simple Browser, directly inside VS Code, at the corresponding (Oracle) JavaDoc page for the class that the selection resolves to. If the underlying `javadoc-url` function doesn't recognize the class, it produces a Google "I feel lucky" URL that will be opened in an _external_ browser instead (since Simple Browser cannot open Google's site). 122 | * `ns.cljs` -- without moving the cursor, evaluate the current file's `ns` form. 123 | * `tap.cljs` -- wrap the current form with `(doto` .. `tap>)` or, in a `->` pipeline, insert `(doto tap>)`. 124 | 125 | > Note: these scripts assume you have a Clojure nREPL connected in Calva to perform symbol/class resolution! 126 | 127 | My `keybindings.json` file has key bindings for these that are intended to match (but override) what would be custom REPL command snippet key bindings, to make these Joyride scripts feel more like snippets: 128 | 129 | * `ctrl+alt+space j` -- runs `javadoc.cljs` as a User-level Joyride script. 130 | * `ctrl+alt+space /` -- runs `clojuredocs.cljs` as a User-level Joyride script (in my Clover setup, this used to be `ctrl+; shift+/`, i,e., `?`, but `shift+/` would be a bit unwieldy as a `ctrl+alt+space` chord). 131 | 132 | In addition, `ctrl+alt+n ctrl+alt+s` will run `ns.cljs`, 133 | and `ctrl+alt+d ctrl+alt+t` will run `tap.cljs`. 134 | 135 | ## Keymap 136 | 137 | Other key bindings that you may or may not find useful: 138 | 139 | * `ctrl+alt+c ctrl+alt+k` -- clear Calva REPL history. 140 | * `ctrl+alt+c z` -- run `clojure-lsp`'s `clean-ns` command on the current namespace. 141 | * `ctrl+alt+e ctrl+alt+j` -- join window groups in VS Code (I often use this after starting the REPL or splitting a window). 142 | * `ctrl+alt+e ctrl+alt+right` -- move the current window to the next group to the right in VS Code (I often use this after starting the REPL or splitting a window). 143 | * `ctrl+alt+e ctrl+alt+w` -- close other editors (useful for decluttering your workspace and focusing on the current file). 144 | * `ctrl+alt+k ctrl+alt+t` -- toggle between Clojure implementation and test files. 145 | * `ctrl+alt+k down` -- move editor to group below. 146 | * `ctrl+alt+k up` -- move editor to group above. 147 | * `ctrl+alt+l ctrl+alt+l` -- convert the selection/word at the cursor to lowercase. 148 | * `ctrl+alt+u ctrl+alt+u` -- convert the selection/word at the cursor to uppercase. 149 | * `ctrl+alt+z` -- clear all notifications. 150 | * `ctrl+t ctrl+f` -- switch focus to the terminal window in VS Code. 151 | * `ctrl+t ctrl+t` -- open a terminal window in VS Code. 152 | 153 | * `alt+home` -- `paredit.openList` for Calva to avoid `ctrl+home` (which should be `cursorTop`!). 154 | * `ctrl+j` -- join lines (this is the default on macOS but not Windows). 155 | 156 | If you use Atlassian/Jira/BitBucket: 157 | 158 | * `ctrl+alt+a ctrl+alt+b` -- switch to BitBucket PRs. 159 | * `ctrl+alt+a ctrl+alt+j` -- switch to Jira issues. 160 | -------------------------------------------------------------------------------- /calva/config.edn: -------------------------------------------------------------------------------- 1 | {:customREPLCommandSnippets 2 | [{:name "Run Current Test" 3 | :key "c" 4 | :snippet (let [crt (try (requiring-resolve 'clojure.test/run-test-var) 5 | (catch Exception _)) 6 | lrt (try (requiring-resolve 'lazytest.repl/run-test-var) 7 | (catch Exception _)) 8 | rks (fn [summary] 9 | ((requiring-resolve 'clojure.set/rename-keys) 10 | summary {:total :test}))] 11 | (binding [clojure.test/*test-out* *out*] 12 | (cond->> {} 13 | crt 14 | (merge-with + (crt (var $top-level-defined-symbol))) 15 | lrt 16 | (merge-with + (rks (lrt (var $top-level-defined-symbol) 17 | {:output 'nested}))))))} 18 | {:name "Tap Define Binding" 19 | :key "d" 20 | :snippet (tap> (def $selection))} 21 | {:name "Tap Last Exception" 22 | :key "e" 23 | :snippet (tap> (let [m (Throwable->map *e)] 24 | (tap> ((requiring-resolve 'clojure.main/ex-triage) m)) 25 | m))} 26 | {:name "Tap Define to Input" 27 | :key "i" 28 | :snippet (tap> (let [v (read-string (read-line))] 29 | (def $selection v)))} 30 | {:name "Portal Clear" 31 | :key "k" 32 | :snippet (do 33 | ((requiring-resolve 'portal.api/clear) 34 | @(requiring-resolve 'dev/portal)) 35 | :portal.api/ignore)} 36 | {:name "Portal Lift Last Logged Value" 37 | :key "l" 38 | :snippet (tap> (:result (first @@(requiring-resolve 'dev/other-taps))))} 39 | {:name "Tap Namespace Publics" 40 | :key "n" 41 | :snippet (tap> 42 | (-> (find-ns '$ns) 43 | (clojure.datafy/datafy) 44 | :publics))} 45 | {:name "Portal Lift Last Output/Report" 46 | :key "o" 47 | :snippet (tap> 48 | (do 49 | (tap> (:stdio (first @@(requiring-resolve 'dev/other-taps)))) 50 | (:report (first @@(requiring-resolve 'dev/other-taps)))))} 51 | {:name "Portal Start" 52 | :key "p" 53 | :snippet (do 54 | (ns dev 55 | (:require [clojure.java.shell :as sh] 56 | [clojure.string :as str])) 57 | ;; we split Portal submissions into two streams: 58 | ;; * middleware and logging output (other-taps) 59 | ;; * everything else (my-taps) 60 | ;; this lets us focus commands on the "interesting" 61 | ;; values while still allowing for tracking of other 62 | ;; stuff happening in the app (logging) or repl (plain 63 | ;; logging) 64 | (defonce ^{:doc "Regular tap>'d values"} 65 | my-taps (atom (with-meta (list) 66 | {:portal.viewer/default 67 | :portal.viewer/inspector}))) 68 | (defonce ^{:doc "Logging and middleware tap>'d values"} 69 | other-taps (atom (with-meta (list) 70 | {:portal.viewer/default 71 | :portal.viewer/inspector}))) 72 | (defn submit* 73 | "The reloadable implementation of submit." 74 | [v] 75 | (let [m (try (meta v) (catch Exception _))] 76 | (if (or (:portal.nrepl/eval m) 77 | (:dev.repl/logging m)) 78 | (when-not (clojure.string/starts-with? (str (:code v)) "(tap>") 79 | (swap! other-taps conj v)) 80 | (swap! my-taps conj v)))) 81 | (defonce ^{:doc "Fixed wrapper around submit*."} 82 | submit (fn [v] (submit* v))) 83 | (def ^{:doc "Atom for current regular value."} 84 | portal 85 | ((requiring-resolve 'portal.api/open) 86 | {:launcher :vs-code 87 | :portal.colors/theme :portal.colors/zerodark 88 | :portal.launcher/window-title (System/getProperty "user.dir") 89 | :value my-taps})) 90 | (def ^{:doc "Atom for other values."} 91 | portal-other 92 | ((requiring-resolve 'portal.api/open) 93 | {:launcher :vs-code 94 | :portal.colors/theme :portal.colors/material-ui 95 | :portal.launcher/window-title "** logging **" 96 | :value other-taps})) 97 | (add-tap submit))} 98 | {:name "Tap Input Code" 99 | :key "q" 100 | :snippet (tap> (let [v (read-string 101 | (clojure.string/replace 102 | (read-line) 103 | "*v" 104 | "(first @@(requiring-resolve 'dev/my-taps))"))] 105 | (eval v)))} 106 | {:name "Run Rich Comment Tests" 107 | :key "r" 108 | :snippet (do 109 | (tap> "Testing Rich Comments in $ns...") 110 | (require '$ns) 111 | ((requiring-resolve 'com.mjdowney.rich-comment-tests/run-ns-tests!) 112 | '$ns))} 113 | {:name "Run Tests" 114 | :key "t" 115 | :snippet (let [crt (try (requiring-resolve 'clojure.test/run-tests) 116 | (catch Exception _)) 117 | lrt (try (requiring-resolve 'lazytest.repl/run-tests) 118 | (catch Exception _)) 119 | rks (fn [summary] 120 | ((requiring-resolve 'clojure.set/rename-keys) 121 | summary {:total :test}))] 122 | (tap> "Testing $ns... ") 123 | (require '$ns) 124 | (cond->> {} 125 | crt 126 | (merge-with + (crt '$ns)) 127 | lrt 128 | (merge-with + (rks (lrt '$ns {:output 'dots})))))} 129 | {:name "Uptime" 130 | :key "u" 131 | :snippet (user/uptime)} 132 | {:name "Run Tests For Source" 133 | :key "x" 134 | :snippet (let [crt (try (requiring-resolve 'clojure.test/run-tests) 135 | (catch Exception _)) 136 | lrt (try (requiring-resolve 'lazytest.repl/run-tests) 137 | (catch Exception _)) 138 | rks (fn [summary] 139 | ((requiring-resolve 'clojure.set/rename-keys) 140 | summary {:total :test}))] 141 | (some (fn [seg] 142 | (let [nt (symbol (str "$ns" "-" seg))] 143 | (when (try (require nt) true 144 | (catch Throwable _)) 145 | (tap> (str "Testing " nt "... ")) 146 | (cond->> {} 147 | crt 148 | (merge-with + (crt nt)) 149 | lrt 150 | (merge-with + (rks (lrt nt {:output 'dots}))))))) 151 | ["test" "expectations"]))} 152 | {:name "Tap Namespace Cleanup" 153 | :key "z" 154 | :snippet (tap> 155 | (when-let [ns (find-ns '$ns)] 156 | (tap> "Removing $ns... ") 157 | (run! (fn [a] 158 | (try (ns-unalias ns a) 159 | (catch Throwable _))) 160 | (keys (ns-aliases ns))) 161 | (run! (fn [i] 162 | (try (ns-unmap ns i) 163 | (catch Throwable _))) 164 | (keys (ns-interns ns))) 165 | (->> (ns-refers ns) 166 | (remove (fn [[_ v]] 167 | (.startsWith (str v) "#'clojure.core/"))) 168 | (map key) 169 | (run! (fn [r] 170 | (try (ns-unmap ns r) 171 | (catch Throwable _)))))))} 172 | {:name "Portal Viewer" 173 | :key "0" 174 | :snippet (do 175 | ((requiring-resolve 'portal.api/eval-str) 176 | @(requiring-resolve 'dev/portal) 177 | (str 178 | '(let [state portal.ui.state/state] 179 | (-> (portal.ui.commands/select-none state) 180 | (.then (fn [] (portal.ui.commands/select-child state))) 181 | (.then (fn [] (portal.ui.commands/select-child state))) 182 | (.then (fn [] (portal.ui.commands/select-next-viewer state))) 183 | (.then (fn [] (portal.ui.commands/select-none state))))))) 184 | :portal.api/ignore)} 185 | {:name "Portal Expand First" 186 | :key "1" 187 | :snippet (do 188 | ((requiring-resolve 'portal.api/eval-str) 189 | @(requiring-resolve 'dev/portal) 190 | (str 191 | '(let [state portal.ui.state/state] 192 | (-> (portal.ui.commands/select-none state) 193 | (.then (fn [] (portal.ui.commands/select-child state))) 194 | (.then (fn [] (portal.ui.commands/select-child state))) 195 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 196 | (.then (fn [] (portal.ui.commands/select-none state))))))) 197 | :portal.api/ignore)} 198 | {:name "Portal Expand Second" 199 | :key "2" 200 | :snippet (do 201 | ((requiring-resolve 'portal.api/eval-str) 202 | @(requiring-resolve 'dev/portal) 203 | (str 204 | '(let [state portal.ui.state/state] 205 | (-> (portal.ui.commands/select-none state) 206 | (.then (fn [] (portal.ui.commands/select-child state))) 207 | (.then (fn [] (portal.ui.commands/select-child state))) 208 | (.then (fn [] (portal.ui.commands/select-child state))) 209 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 210 | (.then (fn [] (portal.ui.commands/select-none state))))))) 211 | :portal.api/ignore)} 212 | {:name "Portal Expand Third" 213 | :key "3" 214 | :snippet (do 215 | ((requiring-resolve 'portal.api/eval-str) 216 | @(requiring-resolve 'dev/portal) 217 | (str 218 | '(let [state portal.ui.state/state] 219 | (-> (portal.ui.commands/select-none state) 220 | (.then (fn [] (portal.ui.commands/select-child state))) 221 | (.then (fn [] (portal.ui.commands/select-child state))) 222 | (.then (fn [] (portal.ui.commands/select-child state))) 223 | (.then (fn [] (portal.ui.commands/select-child state))) 224 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 225 | (.then (fn [] (portal.ui.commands/select-none state))))))) 226 | :portal.api/ignore)} 227 | {:name "Portal Expand Fourth" 228 | :key "4" 229 | :snippet (do 230 | ((requiring-resolve 'portal.api/eval-str) 231 | @(requiring-resolve 'dev/portal) 232 | (str 233 | '(let [state portal.ui.state/state] 234 | (-> (portal.ui.commands/select-none state) 235 | (.then (fn [] (portal.ui.commands/select-child state))) 236 | (.then (fn [] (portal.ui.commands/select-child state))) 237 | (.then (fn [] (portal.ui.commands/select-child state))) 238 | (.then (fn [] (portal.ui.commands/select-child state))) 239 | (.then (fn [] (portal.ui.commands/select-child state))) 240 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 241 | (.then (fn [] (portal.ui.commands/select-none state))))))) 242 | :portal.api/ignore)} 243 | {:name "Portal Expand Fifth" 244 | :key "5" 245 | :snippet (do 246 | ((requiring-resolve 'portal.api/eval-str) 247 | @(requiring-resolve 'dev/portal) 248 | (str 249 | '(let [state portal.ui.state/state] 250 | (-> (portal.ui.commands/select-none state) 251 | (.then (fn [] (portal.ui.commands/select-child state))) 252 | (.then (fn [] (portal.ui.commands/select-child state))) 253 | (.then (fn [] (portal.ui.commands/select-child state))) 254 | (.then (fn [] (portal.ui.commands/select-child state))) 255 | (.then (fn [] (portal.ui.commands/select-child state))) 256 | (.then (fn [] (portal.ui.commands/select-child state))) 257 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 258 | (.then (fn [] (portal.ui.commands/select-none state))))))) 259 | :portal.api/ignore)} 260 | {:name "Portal Expand Sixth" 261 | :key "6" 262 | :snippet (do 263 | ((requiring-resolve 'portal.api/eval-str) 264 | @(requiring-resolve 'dev/portal) 265 | (str 266 | '(let [state portal.ui.state/state] 267 | (-> (portal.ui.commands/select-none state) 268 | (.then (fn [] (portal.ui.commands/select-child state))) 269 | (.then (fn [] (portal.ui.commands/select-child state))) 270 | (.then (fn [] (portal.ui.commands/select-child state))) 271 | (.then (fn [] (portal.ui.commands/select-child state))) 272 | (.then (fn [] (portal.ui.commands/select-child state))) 273 | (.then (fn [] (portal.ui.commands/select-child state))) 274 | (.then (fn [] (portal.ui.commands/select-child state))) 275 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 276 | (.then (fn [] (portal.ui.commands/select-none state))))))) 277 | :portal.api/ignore)} 278 | {:name "Portal Expand Seventh" 279 | :key "7" 280 | :snippet (do 281 | ((requiring-resolve 'portal.api/eval-str) 282 | @(requiring-resolve 'dev/portal) 283 | (str 284 | '(let [state portal.ui.state/state] 285 | (-> (portal.ui.commands/select-none state) 286 | (.then (fn [] (portal.ui.commands/select-child state))) 287 | (.then (fn [] (portal.ui.commands/select-child state))) 288 | (.then (fn [] (portal.ui.commands/select-child state))) 289 | (.then (fn [] (portal.ui.commands/select-child state))) 290 | (.then (fn [] (portal.ui.commands/select-child state))) 291 | (.then (fn [] (portal.ui.commands/select-child state))) 292 | (.then (fn [] (portal.ui.commands/select-child state))) 293 | (.then (fn [] (portal.ui.commands/select-child state))) 294 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 295 | (.then (fn [] (portal.ui.commands/select-none state))))))) 296 | :portal.api/ignore)} 297 | {:name "Portal Expand Eighth" 298 | :key "8" 299 | :snippet (do 300 | ((requiring-resolve 'portal.api/eval-str) 301 | @(requiring-resolve 'dev/portal) 302 | (str 303 | '(let [state portal.ui.state/state] 304 | (-> (portal.ui.commands/select-none state) 305 | (.then (fn [] (portal.ui.commands/select-child state))) 306 | (.then (fn [] (portal.ui.commands/select-child state))) 307 | (.then (fn [] (portal.ui.commands/select-child state))) 308 | (.then (fn [] (portal.ui.commands/select-child state))) 309 | (.then (fn [] (portal.ui.commands/select-child state))) 310 | (.then (fn [] (portal.ui.commands/select-child state))) 311 | (.then (fn [] (portal.ui.commands/select-child state))) 312 | (.then (fn [] (portal.ui.commands/select-child state))) 313 | (.then (fn [] (portal.ui.commands/select-child state))) 314 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 315 | (.then (fn [] (portal.ui.commands/select-none state))))))) 316 | :portal.api/ignore)} 317 | {:name "Portal Expand Ninth" 318 | :key "9" 319 | :snippet (do 320 | ((requiring-resolve 'portal.api/eval-str) 321 | @(requiring-resolve 'dev/portal) 322 | (str 323 | '(let [state portal.ui.state/state] 324 | (-> (portal.ui.commands/select-none state) 325 | (.then (fn [] (portal.ui.commands/select-child state))) 326 | (.then (fn [] (portal.ui.commands/select-child state))) 327 | (.then (fn [] (portal.ui.commands/select-child state))) 328 | (.then (fn [] (portal.ui.commands/select-child state))) 329 | (.then (fn [] (portal.ui.commands/select-child state))) 330 | (.then (fn [] (portal.ui.commands/select-child state))) 331 | (.then (fn [] (portal.ui.commands/select-child state))) 332 | (.then (fn [] (portal.ui.commands/select-child state))) 333 | (.then (fn [] (portal.ui.commands/select-child state))) 334 | (.then (fn [] (portal.ui.commands/select-child state))) 335 | (.then (fn [] (portal.ui.commands/toggle-expand state))) 336 | (.then (fn [] (portal.ui.commands/select-none state))))))) 337 | :portal.api/ignore)}]} 338 | -------------------------------------------------------------------------------- /clojure-lsp/config.edn: -------------------------------------------------------------------------------- 1 | {:cljfmt 2 | {:extra-indents 3 | {describe [[:block 1]] 4 | expecting [[:block 1]] 5 | it [[:block 1]] 6 | m/match [[:block 0]]}}} 7 | -------------------------------------------------------------------------------- /joyride/scripts/clojuredocs.cljs: -------------------------------------------------------------------------------- 1 | (ns clojuredocs 2 | (:require ["ext://betterthantomorrow.calva$v1.repl" :refer [evaluateCode]] 3 | ["ext://betterthantomorrow.calva$v1.document" :refer [getNamespace]] 4 | ["vscode" :as vscode] 5 | [clojure.edn :as edn] 6 | [promesa.core :as p])) 7 | 8 | (defn- selected-text [] 9 | (vscode/commands.executeCommand "calva.selectCurrentForm") 10 | (let [editor ^js vscode/window.activeTextEditor 11 | selection (.-selection editor)] 12 | (.getText (.-document editor) selection))) 13 | 14 | (defn clojuredocs-url [code] 15 | (str 16 | " (str \"https://clojuredocs.org/\"" 17 | " (-> (str (symbol #'" code "))" 18 | ;; clean up ? ! & 19 | " (clojure.string/replace \"?\" \"%3f\")" 20 | " (clojure.string/replace \"!\" \"%21\")" 21 | " (clojure.string/replace \"&\" \"%26\")" 22 | "))")) 23 | 24 | (-> (p/let [code (clojuredocs-url (selected-text)) 25 | resp (evaluateCode "clj" code (getNamespace)) 26 | url (edn/read-string (.-result resp))] 27 | (vscode/commands.executeCommand "simpleBrowser.show" url)) 28 | (p/catch (fn [e] (println (str "Evaluation error: " e))))) 29 | -------------------------------------------------------------------------------- /joyride/scripts/example_repl.cljs: -------------------------------------------------------------------------------- 1 | (ns example-repl 2 | (:require [remote-repl :as r])) 3 | 4 | (r/repl-setup 6666 7777 "QA" "qauser@10.10.10.10") 5 | -------------------------------------------------------------------------------- /joyride/scripts/javadoc.cljs: -------------------------------------------------------------------------------- 1 | (ns javadoc 2 | (:require ["ext://betterthantomorrow.calva$v1.repl" :refer [evaluateCode]] 3 | ["ext://betterthantomorrow.calva$v1.document" :refer [getNamespace]] 4 | ["vscode" :as vscode] 5 | [clojure.edn :as edn] 6 | [clojure.string :as str] 7 | [promesa.core :as p])) 8 | 9 | (defn- selected-text [] 10 | (vscode/commands.executeCommand "calva.selectCurrentForm") 11 | (let [editor ^js vscode/window.activeTextEditor 12 | selection (.-selection editor)] 13 | (.getText (.-document editor) selection))) 14 | 15 | (defn javadoc-url [code] 16 | (str 17 | "(let [c-o-o " code 18 | " ^Class c (if (instance? Class c-o-o) c-o-o (class c-o-o))] " 19 | " ((requiring-resolve 'clojure.java.javadoc/add-remote-javadoc)" 20 | " \"java.\" \"https://docs.oracle.com/en/java/javase/21/docs/api/%s/\")" 21 | " ((requiring-resolve 'clojure.java.javadoc/add-remote-javadoc)" 22 | " \"javax.\" \"https://docs.oracle.com/en/java/javase/21/docs/api/%s/\")" 23 | " (->" 24 | " ((requiring-resolve 'clojure.java.javadoc/javadoc-url)" 25 | " (.getName c))" 26 | " (clojure.string/replace" ; strip inner class 27 | " #\"\\$[a-zA-Z0-9_]+\" \"\")" 28 | " (clojure.string/replace" ; force https 29 | " #\"^http:\" \"https:\")" 30 | "))")) 31 | 32 | (-> (p/let [code (javadoc-url (selected-text)) 33 | resp (evaluateCode "clj" code (getNamespace)) 34 | url (edn/read-string (.-result resp))] 35 | (if (str/starts-with? url "https://www.google.com") 36 | (vscode/commands.executeCommand "vscode.open" url) 37 | (vscode/commands.executeCommand "simpleBrowser.show" url))) 38 | (p/catch (fn [e] (println (str "Evaluation error: " e))))) 39 | -------------------------------------------------------------------------------- /joyride/scripts/ns.cljs: -------------------------------------------------------------------------------- 1 | (ns ns 2 | (:require ["ext://betterthantomorrow.calva$v1" :as calva])) 3 | 4 | (let [[ns-name ns-form] (calva/document.getNamespaceAndNsForm)] 5 | (-> (calva/repl.evaluateCode "clj" (str "(clojure.core/tap> \"evaluating " 6 | ns-name 7 | "...\")")) 8 | (.then 9 | (fn [_] 10 | (calva/repl.evaluateCode "clj" ns-form))) 11 | (.then 12 | (fn [ns-val] 13 | (calva/repl.evaluateCode "clj" (str "(clojure.core/tap> \"" 14 | (.-ns ns-val) 15 | " evaluated\")")))))) 16 | -------------------------------------------------------------------------------- /joyride/scripts/tap.cljs: -------------------------------------------------------------------------------- 1 | (ns tap 2 | (:require ["ext://betterthantomorrow.calva$v1" :as calva] 3 | ["vscode" :as vscode] 4 | [promesa.core :as p])) 5 | 6 | (p/let [[_ f] (calva/ranges.currentFunction) 7 | p (-> vscode/window.activeTextEditor 8 | .-selection 9 | .-active) 10 | [r s] (if (= "->" f) 11 | [(vscode/Range. p p) nil] 12 | (calva/ranges.currentForm))] 13 | (calva/editor.replace vscode/window.activeTextEditor r 14 | (str "(doto " s (when s " ") "tap>)"))) 15 | -------------------------------------------------------------------------------- /joyride/src/remote_repl.cljs: -------------------------------------------------------------------------------- 1 | (ns remote-repl 2 | (:require ["ext://betterthantomorrow.calva$v1" :as calva] 3 | ["fs" :as fs] 4 | ["path" :as path] 5 | ["vscode" :as vscode] 6 | [clojure.edn :as edn] 7 | [promesa.core :as p])) 8 | 9 | (defn- start-tunnel [nrepl-port portal-port extension-port label remote-server] 10 | (let [terminal (vscode/window.createTerminal #js {:isTransient true 11 | :name label 12 | :message (str label " Remote REPL...")})] 13 | (.show terminal) 14 | (.sendText terminal (str "ssh -C -N" 15 | " -L " nrepl-port ":localhost:" nrepl-port 16 | " -L " portal-port ":localhost:" portal-port 17 | " -R " extension-port ":localhost:" extension-port 18 | " " remote-server)))) 19 | 20 | (defn- connect-repl [nrepl-port] 21 | (vscode/commands.executeCommand "calva.disconnect") 22 | (vscode/commands.executeCommand "calva.connect" #js {:port nrepl-port :connectSequence "Generic"})) 23 | 24 | (defn- portal-config [] 25 | (-> vscode/workspace.workspaceFolders 26 | first 27 | .-uri 28 | .-fsPath 29 | (path/join ".portal/vs-code.edn") 30 | (fs/readFileSync #js {:encoding "utf8"}) 31 | edn/read-string)) 32 | 33 | (defn repl-setup [nrepl-port portal-port label remote-server] 34 | (let [config (portal-config)] 35 | (start-tunnel nrepl-port portal-port (:port config) label remote-server) 36 | (p/do 37 | (p/delay 2000) 38 | (connect-repl nrepl-port) 39 | (p/delay 1000) 40 | (calva/repl.evaluateCode "clj" (pr-str (list 'spit ".portal/vs-code.edn" config)))))) 41 | -------------------------------------------------------------------------------- /keybindings.json: -------------------------------------------------------------------------------- 1 | // Place your key bindings in this file to override the defaultsauto[] 2 | [ 3 | { 4 | "key": "ctrl+alt+e ctrl+alt+j", 5 | "command": "workbench.action.joinTwoGroups" 6 | }, 7 | { 8 | "key": "ctrl+j", 9 | "command": "editor.action.joinLines" 10 | }, 11 | { 12 | "key": "ctrl+alt+a ctrl+alt+b", 13 | "command": "atlascode.views.bb.pullrequestsTreeView.focus" 14 | }, 15 | { 16 | "key": "ctrl+alt+a ctrl+alt+j", 17 | "command": "atlascode.views.jira.customJql.focus" 18 | }, 19 | { 20 | "key": "ctrl+t ctrl+f", 21 | "command": "workbench.action.terminal.focus" 22 | }, 23 | { 24 | "key": "ctrl+t ctrl+t", 25 | "command": "workbench.action.quickOpenTerm" 26 | }, 27 | { 28 | "key": "ctrl+alt+u ctrl+alt+u", 29 | "command": "editor.action.transformToUppercase" 30 | }, 31 | { 32 | "key": "ctrl+alt+l ctrl+alt+l", 33 | "command": "editor.action.transformToLowercase" 34 | }, 35 | { 36 | "key": "ctrl+alt+e ctrl+alt+right", 37 | "command": "workbench.action.moveEditorToRightGroup" 38 | }, 39 | { 40 | "key": "ctrl+alt+k ctrl+alt+t", 41 | "command": "calva.toggleBetweenImplAndTest" 42 | }, 43 | { 44 | "key": "ctrl+alt+space j", 45 | "command": "joyride.runUserScript", 46 | "args": "javadoc.cljs" 47 | }, 48 | { 49 | "key": "ctrl+alt+space /", 50 | "command": "joyride.runUserScript", 51 | "args": "clojuredocs.cljs" 52 | }, 53 | { 54 | "key": "ctrl+alt+b q", 55 | "command": "joyride.runUserScript", 56 | "args": "qa_repl.cljs" 57 | }, 58 | { 59 | "key": "ctrl+alt+b p", 60 | "command": "joyride.runUserScript", 61 | "args": "prod_repl.cljs" 62 | }, 63 | { 64 | "key": "ctrl+alt+n ctrl+alt+s", 65 | "command": "joyride.runUserScript", 66 | "args": "ns.cljs" 67 | }, 68 | { 69 | "key": "ctrl+alt+d ctrl+alt+t", 70 | "command": "joyride.runUserScript", 71 | "args": "tap.cljs" 72 | }, 73 | { 74 | "key": "ctrl+alt+e ctrl+alt+w", 75 | "command": "workbench.action.closeOtherEditors" 76 | }, 77 | { 78 | "key": "ctrl+alt+z", 79 | "command": "notifications.clearAll" 80 | }, 81 | { 82 | "key": "alt+home", 83 | "command": "paredit.openList", 84 | "when": "calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/" 85 | }, 86 | { 87 | "key": "ctrl+home", 88 | "command": "-paredit.openList", 89 | "when": "calva:keybindingsEnabled && editorTextFocus && editorLangId == 'clojure' && paredit:keyMap =~ /original|strict/" 90 | }, 91 | { 92 | "command": "paredit.insertSemiColon", 93 | "key": ";", 94 | "when": "calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment" 95 | }, 96 | { 97 | "key": "ctrl+alt+c z", 98 | "command": "clojureLsp.refactor.cleanNs" 99 | }, 100 | { 101 | "key": "ctrl+alt+c ctrl+alt+q", 102 | "command": "calva.disconnect" 103 | }, 104 | { 105 | "key": "ctrl+alt+c ctrl+alt+k", 106 | "command": "calva.clearReplHistory" 107 | }, 108 | { 109 | "key": "ctrl+shift+q q", 110 | "command": "workbench.action.quickOpenNavigatePreviousInViewPicker", 111 | "when": "inQuickOpen && inViewsPicker" 112 | }, 113 | { 114 | "key": "ctrl+shift+q", 115 | "command": "-workbench.action.quickOpenNavigatePreviousInViewPicker", 116 | "when": "inQuickOpen && inViewsPicker" 117 | }, 118 | { 119 | "key": "ctrl+shift+q e", 120 | "command": "copilotSidebar.explain.focus" 121 | }, 122 | { 123 | "key": "ctrl+shift+q t", 124 | "command": "copilotSidebar.generateTests.focus" 125 | }, 126 | { 127 | "key": "ctrl+alt+k up", 128 | "command": "workbench.action.moveEditorToAboveGroup" 129 | }, 130 | { 131 | "key": "ctrl+alt+k down", 132 | "command": "workbench.action.moveEditorToBelowGroup" 133 | }, 134 | { 135 | "key": "ctrl+alt+n ctrl+alt+f", 136 | "command": "explorer.newFolder" 137 | }, 138 | { 139 | "key": "ctrl+enter", 140 | "command": "-github.copilot.generate", 141 | "when": "editorTextFocus && github.copilot.activated && !inInteractiveInput && !interactiveEditorFocused" 142 | }, 143 | { 144 | "key": "ctrl+shift+g ctrl+shift+s", 145 | "command": "git.sync" 146 | }, 147 | { 148 | "key": "ctrl+alt+v ctrl+alt+t", 149 | "command": "workbench.view.extension.test" 150 | }, 151 | { 152 | "key": "ctrl+alt+l ctrl+alt+f", 153 | "command": "liveshare.follow", 154 | "when": "liveshare:hasCollaborators && !liveshare:isFollowing" 155 | }, 156 | { 157 | "key": "ctrl+alt+f", 158 | "command": "-liveshare.follow", 159 | "when": "liveshare:hasCollaborators && !liveshare:isFollowing" 160 | }, 161 | { 162 | "key": "ctrl+alt+l ctrl+alt+/", 163 | "command": "liveshare.followToTheSide", 164 | "when": "liveshare:hasCollaborators" 165 | }, 166 | { 167 | "key": "ctrl+alt+/", 168 | "command": "-liveshare.followToTheSide", 169 | "when": "liveshare:hasCollaborators" 170 | }, 171 | { 172 | "key": "ctrl+alt+l ctrl+alt+j", 173 | "command": "liveshare.join", 174 | "when": "liveshare:state != 'Joined' && liveshare:state != 'Shared'" 175 | }, 176 | { 177 | "key": "ctrl+alt+j", 178 | "command": "-liveshare.join", 179 | "when": "liveshare:state != 'Joined' && liveshare:state != 'Shared'" 180 | }, 181 | { 182 | "key": "ctrl+alt+l ctrl+alt+f", 183 | "command": "liveshare.unfollow", 184 | "when": "liveshare:hasCollaborators && liveshare:isFollowing" 185 | }, 186 | { 187 | "key": "ctrl+alt+f", 188 | "command": "-liveshare.unfollow", 189 | "when": "liveshare:hasCollaborators && liveshare:isFollowing" 190 | }, 191 | { 192 | "key": "ctrl+alt+c up", 193 | "command": "editor.action.insertCursorAbove", 194 | "when": "editorTextFocus" 195 | }, 196 | { 197 | "key": "ctrl+alt+up", 198 | "command": "-editor.action.insertCursorAbove", 199 | "when": "editorTextFocus" 200 | }, 201 | { 202 | "key": "ctrl+alt+c down", 203 | "command": "editor.action.insertCursorBelow", 204 | "when": "editorTextFocus" 205 | }, 206 | { 207 | "key": "ctrl+alt+down", 208 | "command": "-editor.action.insertCursorBelow", 209 | "when": "editorTextFocus" 210 | }, 211 | { 212 | "key": "ctrl+alt+a ctrl+alt+s", 213 | "command": "workbench.action.files.saveFiles" 214 | }, 215 | { 216 | "key": "ctrl+alt+right", 217 | "command": "editor.action.inlineSuggest.acceptNextWord", 218 | "when": "inlineSuggestionVisible && !editorReadonly" 219 | }, 220 | { 221 | "key": "ctrl+right", 222 | "command": "-editor.action.inlineSuggest.acceptNextWord", 223 | "when": "inlineSuggestionVisible && !editorReadonly" 224 | }, 225 | { 226 | "key": "ctrl+shift+g ctrl+shift+b", 227 | "command": "gitlens.toggleLineBlame" 228 | }, 229 | { 230 | "key": "ctrl+alt+c right", 231 | "command": "editor.action.insertCursorAtEndOfEachLineSelected", 232 | "when": "editorTextFocus" 233 | }, 234 | { 235 | "key": "shift+alt+i", 236 | "command": "-editor.action.insertCursorAtEndOfEachLineSelected", 237 | "when": "editorTextFocus" 238 | }, 239 | { 240 | "key": "shift+alt+i", 241 | "command": "inlineChat.start", 242 | "when": "editorFocus && inlineChatHasProvider && inlineChatPossible && !editorReadonly" 243 | }, 244 | { 245 | "key": "ctrl+i", 246 | "command": "-inlineChat.start", 247 | "when": "editorFocus && inlineChatHasProvider && inlineChatPossible && !editorReadonly" 248 | }, 249 | { 250 | "key": "ctrl+shift+g g", 251 | "command": "workbench.view.scm", 252 | "when": "workbench.scm.active" 253 | }, 254 | { 255 | "key": "ctrl+shift+g g", 256 | "command": "-workbench.view.scm", 257 | "when": "workbench.scm.active && !gitlens:disabled && config.gitlens.keymap == 'chorded'" 258 | }, 259 | { 260 | "key": "ctrl+tab", 261 | "command": "editor.action.inlineSuggest.jump", 262 | "when": "inlineEditIsVisible && tabShouldJumpToInlineEdit && !editorHoverFocused && !editorTabMovesFocus && !suggestWidgetVisible" 263 | }, 264 | { 265 | "key": "tab", 266 | "command": "-editor.action.inlineSuggest.jump", 267 | "when": "inlineEditIsVisible && tabShouldJumpToInlineEdit && !editorHoverFocused && !editorTabMovesFocus && !suggestWidgetVisible" 268 | }, 269 | { 270 | "key": "ctrl+alt+a ctrl+alt+j", 271 | "command": "atlascode.views.jira.assignedWorkItemsTreeView.focus" 272 | } 273 | ] 274 | -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "calva.autoConnectRepl": true, 3 | "calva.autoOpenInspector": false, 4 | "calva.autoOpenREPLWindow": false, 5 | "calva.autoStartRepl": false, 6 | "calva.clojureLspVersion": "nightly", 7 | "calva.customREPLHoverSnippets": [], 8 | "calva.enableJSCompletions": false, 9 | "calva.evaluationSendCodeToOutputWindow": false, 10 | "calva.fiddleFilePaths": [], 11 | "calva.fmt.configPath": "CLOJURE-LSP", 12 | "calva.highlight.cycleBracketColors": false, 13 | "calva.highlight.enableBracketColors": false, 14 | "calva.highlight.highlightActiveIndent": false, 15 | "calva.jackInEnv": {}, 16 | "calva.openBrowserWhenFigwheelStarted": false, 17 | "calva.paredit.defaultKeyMap": "strict", 18 | "calva.paredit.killAlsoCutsToClipboard": true, 19 | "calva.paredit.multicursor": true, 20 | "calva.redirectServerOutputToRepl": false, 21 | "calva.referencesCodeLens.enabled": true, 22 | "calva.showCalvaSaysOnStart": false, 23 | "calva.showDocstringInParameterHelp": true, 24 | "calva.useLegacyReplWindowPath": false, 25 | "calva.useLiveShare": true, 26 | "calva.useTestExplorer": true, 27 | "calva.autoEvaluateCode": { 28 | "onConnect": { 29 | "clj": "(when-let [requires (resolve 'clojure.main/repl-requires)] (clojure.core/apply clojure.core/require @requires))", 30 | "cljs": "(try (require '[cljs.repl :refer [apropos dir doc find-doc print-doc pst source]]) (catch :default e (js/console.warn \"Failed to require cljs.repl utilities:\" (.-message e))))" 31 | }, 32 | "onFileLoaded": { 33 | "clj": null, 34 | "cljs": null 35 | } 36 | }, 37 | "calva.jackInDependencyVersions": { 38 | "nrepl": "1.3.1", 39 | "cider-nrepl": "0.55.7", 40 | "cider/piggieback": "0.6.0" 41 | }, 42 | "calva.myCljAliases": [ 43 | ":1.12", 44 | ":portal", 45 | ":dev/repl" 46 | ], 47 | "calva.outputDestinations": { 48 | "evalResults": "terminal", 49 | "evalOutput": "terminal", 50 | "otherOutput": "terminal" 51 | }, 52 | "calva.prettyPrintingOptions": { 53 | "printEngine": "calva", 54 | "enabled": true, 55 | "width": 120, 56 | "maxLength": 50 57 | }, 58 | "calva.replConnectSequences": [ 59 | { 60 | "name": "Loaded deps.edn Jack-In", 61 | "projectType": "deps.edn", 62 | "cljsType": "none", 63 | "autoSelectForJackIn": false, 64 | "projectRootPath": ["."], 65 | "menuSelections": { 66 | "cljAliases": ["1.12", "dev/repl", "portal", "test", "no-main"] 67 | } 68 | }, 69 | { 70 | "name": "Assumed deps.edn Connect", 71 | "projectType": "deps.edn", 72 | "autoSelectForConnect": true 73 | } 74 | ], 75 | "calva-backseat-driver.autoStartMCPServer": true, 76 | "calva-backseat-driver.enableReplEvaluation": true, 77 | "[clojure]": { 78 | "diffEditor.ignoreTrimWhitespace": true, 79 | "editor.autoClosingBrackets": "always", 80 | "editor.autoClosingOvertype": "always", 81 | "editor.autoClosingQuotes": "always", 82 | "editor.autoIndent": "advanced", 83 | "editor.formatOnPaste": true, 84 | "editor.formatOnType": true, 85 | "editor.matchBrackets": "near", 86 | "editor.wordSeparators": "\t ()\"':,;~@#$%^&{}[]`", 87 | "files.trimFinalNewlines": true, 88 | "files.trimTrailingWhitespace": true, 89 | }, 90 | "accessibility.voice.keywordActivation": "chatInContext", 91 | "chat.experimental.statusIndicator.enabled": true, 92 | "clock.alignment": "Right", 93 | "clock.format": "HH:MM:ss", 94 | "clojure.trace.server": "messages", 95 | "cSpell.diagnosticLevel": "Hint", 96 | "cSpell.diagnosticLevelFlaggedWords": "Hint", 97 | "cSpell.textDecoration": "underline dotted lightblue", 98 | "cSpell.textDecorationColor": "lightblue", 99 | "cSpell.overviewRulerColor": "lightblue", 100 | "cSpell.userWords": [ 101 | "classloader", 102 | "classpath", 103 | "Cognitect", 104 | "pluggable", 105 | "Polylith", 106 | "subproject", 107 | "swappable", 108 | "uberjars" 109 | ], 110 | "diffEditor.codeLens": true, 111 | "diffEditor.diffAlgorithm": "advanced", 112 | "diffEditor.ignoreTrimWhitespace": true, 113 | "editor.accessibilitySupport": "off", 114 | "editor.bracketPairColorization.enabled": true, 115 | "editor.cursorStyle": "block", 116 | "editor.detectIndentation": false, 117 | "editor.fontFamily": "Fira Code", 118 | "editor.fontLigatures": true, 119 | "editor.fontSize": 18, 120 | "editor.guides.bracketPairs": true, 121 | "editor.guides.bracketPairsHorizontal": true, 122 | "editor.hover.above": false, 123 | "editor.hover.delay": 1500, 124 | "editor.inlineSuggest.enabled": true, 125 | "editor.largeFileOptimizations": false, 126 | "editor.multiDocumentOccurrencesHighlight": true, 127 | "editor.quickSuggestionsDelay": 1000, 128 | "editor.stickyScroll.enabled": true, 129 | "editor.suggestSelection": "first", 130 | "editor.tabSize": 2, 131 | "editor.wordWrapColumn": 78, 132 | "editor.rulers": [ 133 | 80 134 | ], 135 | "emmet.showExpandedAbbreviation": "never", 136 | "explorer.confirmDragAndDrop": false, 137 | "explorer.excludeGitIgnore": true, 138 | "extensions.ignoreRecommendations": true, 139 | "files.insertFinalNewline": true, 140 | "files.trimFinalNewlines": true, 141 | "files.trimTrailingWhitespace": true, 142 | "files.associations": { 143 | "*.cljr": "clojure", 144 | "*.clj_kondo": "clojure" 145 | }, 146 | "files.exclude": { 147 | "**/.classpath": true, 148 | "**/.clj-kondo/.cache": true, 149 | "**/.cpcache": true, 150 | "**/.lsp/.cache": true, 151 | "**/.project": true, 152 | "**/.settings": true, 153 | "**/.factorypath": true 154 | }, 155 | "files.watcherExclude": { 156 | "**/.clj-kondo/.cache/**": true, 157 | "**/.lsp/.cache/**": true, 158 | "**/target/classes/**": true 159 | }, 160 | "git.alwaysShowStagedChangesResourceGroup": true, 161 | "git.alwaysSignOff": true, 162 | "git.blame.editorDecoration.enabled": true, 163 | "git.blame.statusBarItem.enabled": true, 164 | "git.confirmSync": false, 165 | "git.enableCommitSigning": true, 166 | "git.enableSmartCommit": true, 167 | "git.openRepositoryInParentFolders": "always", 168 | "git.pullTags": false, 169 | "github.copilot-labs.showBrushesLenses": true, 170 | "github.copilot-labs.showTestGenerationLenses": true, 171 | "github.copilot.advanced": {}, 172 | "github.copilot.chat.editor.temporalContext.enabled": true, 173 | "github.copilot.editor.enableAutoCompletions": true, 174 | "github.copilot.nextEditSuggestions.enabled": true, 175 | "github.copilot.nextEditSuggestions.fixes": true, 176 | "github.copilot.chat.reviewSelection.instructions": [ 177 | {"text":"Do not suggest splitting let into multiple bindings"} 178 | ], 179 | "github.copilot.enable": { 180 | "*": true, 181 | "plaintext": false, 182 | "markdown": true, 183 | "scminput": false 184 | }, 185 | "gitlens.advanced.blame.delayAfterEdit": 10000, 186 | "gitlens.currentLine.enabled": false, 187 | "gitlens.launchpad.indicator.enabled": false, 188 | "gitlens.mode.active": "zen", 189 | "gitlens.plusFeatures.enabled": false, 190 | "gitlens.virtualRepositories.enabled": false, 191 | "inlineChat.enableV2": true, 192 | "inlineChat.showDiff": false, 193 | "javascript.referencesCodeLens.enabled": true, 194 | "javascript.referencesCodeLens.showOnAllFunctions": true, 195 | "jest.jestCommandLine": "npx yarn jest", 196 | "liveshare.accessibility.voiceEnabled": true, 197 | "liveshare.guestApprovalRequired": true, 198 | "liveshare.launcherClient": "visualStudioCode", 199 | "redhat.telemetry.enabled": true, 200 | "remote.autoForwardPortsSource": "hybrid", 201 | "rewrap.doubleSentenceSpacing": true, 202 | "rewrap.wrappingColumn": 78, 203 | "scm.inputFontFamily": "editor", 204 | "search.exclude": { 205 | "**/.calva/output-window/output.calva-repl": true, 206 | ".calva/output-window/output.calva-repl": true 207 | }, 208 | "security.workspace.trust.untrustedFiles": "open", 209 | "settingsSync.ignoredSettings": [ 210 | "yaml.schemas", 211 | "editor.fontSize" 212 | ], 213 | "task.saveBeforeRun": "never", 214 | "terminal.integrated.enableMultiLinePasteWarning": false, 215 | "terminal.integrated.fontLigatures.enabled": true, 216 | "terminal.integrated.fontLigatures.featureSettings": "", 217 | "terminal.integrated.shellIntegration.history": 1000, 218 | "window.density.editorTabHeight": "compact", 219 | "window.zoomLevel": -1, 220 | "workbench.activityBar.location": "top", 221 | "workbench.colorTheme": "Default Dark+", 222 | "workbench.editor.empty.hint": "hidden", 223 | "workbench.editor.highlightModifiedTabs": true, 224 | "workbench.editor.pinnedTabsOnSeparateRow": true, 225 | "workbench.preferredDarkColorTheme": "Default Dark+", 226 | "workbench.startupEditor": "newUntitledFile", 227 | "workbench.tree.enableStickyScroll": true, 228 | "yaml.schemas": { 229 | "file:///home/sean/.vscode-server/extensions/atlassian.atlascode-3.8.2/resources/schemas/pipelines-schema.json": "bitbucket-pipelines.yml" 230 | }, 231 | "atlascode.bitbucket.enabled": true, 232 | "atlascode.bitbucket.issues.explorerEnabled": false, 233 | "atlascode.bitbucket.pipelines.explorerEnabled": false, 234 | "atlascode.bitbucket.statusbar.enabled": false, 235 | "atlascode.jira.enabled": true, 236 | "atlascode.jira.explorer.nestSubtasks": false, 237 | "atlascode.jira.statusbar.enabled": true, 238 | "atlascode.jira.statusbar.showLogin": false, 239 | "atlascode.jira.statusbar.showProduct": false, 240 | "atlascode.jira.statusbar.showUser": false, 241 | "atlascode.jira.jqlList": [ 242 | { 243 | "id": "eb6b067c-8124-43d4-aa91-41052ca528d9", 244 | "enabled": true, 245 | "name": "My wsnetworks Issues", 246 | "query": "((assignee = currentUser() AND status != Backlog AND status != 'To Do') OR (reporter = currentUser() AND createdDate > startOfDay())) AND type != Epic AND status in (Backlog,\"To Do\",\"New\",\"More Information Needed\",\"Selected For Development\",\"In Progress\") ORDER BY status ASC, lastViewed DESC", 247 | "siteId": "cf226917-740d-419c-9013-ad19765f9a1d", 248 | "monitor": true 249 | } 250 | ], 251 | "atlascode.jira.lastCreateSiteAndProject": { 252 | "siteId": "cf226917-740d-419c-9013-ad19765f9a1d", 253 | "projectKey": "WS" 254 | }, 255 | } 256 | --------------------------------------------------------------------------------