hyperfiddle

tobias 2025-03-11T09:07:08.822049Z

Can I check I've understood the token explainer tutorial correctly? https://electric.hyperfiddle.net/tutorial/token_explainer What I believe is: • On L15, t and err are signals. Initially both nil • As soon as button is clicked, t becomes non-nil, which changes button styles thanks to lines 16 & 17. However err remains nil for the time being. • t becoming non-nil is what causes the when-some to succeed and mounts the (let ...) branch on L 20, which is what makes the call to the server. • As soon as (t) or (t res) are called, t becomes nil, again changing styles thanks to lines 16 & 17 • If (t res) is called, err is set to the value of res and this propagates back to L18 to set :aria-invalid. Is that correct? Thanks for answering my ELI5 questions - it's just taking me a little while to wrap my head around this pattern 😅

xificurC 2025-03-11T09:21:56.844149Z

it is correct. Do you have any feedback on the explainer, or the API?

tobias 2025-03-11T12:17:09.518229Z

Thanks for confirming! Explainer was good. Maybe I'd suggest just a few of the bullets could be reworded for clarity: • (edited bullet): When t becomes non-nil, (when-some [t ...] succeeds and the when-body is mounted. Mounting the when-body makes the call to the server followed by calling (t) or (t res) , either of which set t to nil, disabling the button (lines 16 and 17) to prevent future events, i.e. "backpressure the user", who is the source of events. • (new bullet): In the error case, calling (t res) sets the value of the err signal on L18 to non-nil, changing, turning the button pink. • ... • (edited bullet:) Invoke the token as a function (t ...) to spend the token, which will turn it nil, which will unmount the when-body and remove the disabled state from the button so it can receive the next event.

tobias 2025-03-11T12:22:41.487809Z

I really appreciate these tutorials you and the team put together. I'm following Dustin's advice of typing out every tutorial on my machine to make sure I really understand it, otherwise it's too easy to skim over and kid myself that I understand.

tobias 2025-03-11T12:24:27.219999Z

Token API seems a bit more verbose than v2 but I'm happy to trust what you say in the tutorial that it's powerful and will grow on me 👍

xificurC 2025-03-11T12:26:59.106939Z

Thank you for the feedback

xificurC 2025-03-11T12:29:03.288779Z

Re token API I'd say one can implement the old dom/on API with tokens but not vice versa. E.g. the forms abstractions require tokens

2025-03-11T15:25:53.794229Z

I’ve added an underlining option to my Emacs minor mode. See thread.

👀 2
2025-03-12T11:35:51.929409Z

I can fix this to an extent. Here’s where I’ve got to with the DirTree example:

2025-03-12T11:36:55.111499Z

I”m not coloring Electric calls themselves, but — not shown in that example — I am recursively coloring their args.

2025-03-12T11:38:19.114209Z

It needs an understanding of all Electric forms that make bindings (`e/defn`, let, e/for. e/fn, …), and it needs to understand destructuring.

2025-03-12T11:40:30.535609Z

Some way to go, and it won’t understand any new binding forms that I don’t teach it. So any userland macros that create bindings will be an issue. Unless I come up with an extension mechanism.

2025-03-12T11:58:08.540169Z

An example with non-trivial args in an Electric call:

2025-03-12T12:01:26.646199Z

Improved example, changing a to x:

hkjels 2025-03-12T12:19:40.930739Z

Ohh. I made a package for this same thing previously, just didn't do the work to open-source it. Nice to see that you went a step further 🙂

2025-03-12T12:41:04.009699Z

@hkjels Oh, cool. How far did you get with it?

Tommy Jolly 2025-03-12T13:28:01.992099Z

Alternative installation for Emacs 30+

(use-package nomis-electric-clojure
  :vc (:url ""
       :rev "newest")
  :ensure t)

Tommy Jolly 2025-03-12T13:28:47.564479Z

might be worth putting in the README

2025-03-12T13:49:56.763959Z

> Alternative installation for Emacs 30+ Thanks! I’ve added that.

hkjels 2025-03-12T13:58:12.272099Z

Actually, I see now that it's just part of my clojure config, so not very far 😄

(use-package clojure-ts-mode
  :defer t
  :commands (clojure-ts-mode)
  :mode (("\\.clj\\(?:c\\|s\\)?\\'" . clojure-ts-mode)
         ("\\.edn\\'" . clojure-ts-mode))
  :hook ((clojure-ts-mode . cider-mode)
         (clojure-ts-mode . jarchive-mode)
         (clojure-ts-mode . eglot-ensure)
         (clojure-ts-mode . clojure-highlight-db-ident-keyword)
         (clojure-ts-mode . clojure-add-electric-keywords))
  :config
  (defun clojure-setup-electric-prettify ()
    "Prettify e/client and e/server symbols."
    (setq prettify-symbols-alist
          '(("e/client" . "λ")
            ("e/server" . "⚙"))))
  (defface clojure-db-ident-keyword-face
    '((t (:foreground "#ffa500")))
    "Custom face for the keyword following :db/ident.")
  (defface clojure-e-client-face
    '((t (:background "#fafafa")))
    "Face for e/client sexp.")
  (defface clojure-e-server-face
    '((t (:background "#f3f3f3")))
    "Face for e/server sexp.")
  (defun clojure-highlight-electric-blocks (limit)
    "Highlight e/client and e/server blocks up to LIMIT."
    (while (re-search-forward "(e/\\(client\\|server\\)" limit t)
      (let ((sexp-end (find-sexp-end)))
        (when sexp-end
          (put-text-property (match-beginning 0) sexp-end
                             'face (if (equal (match-string 1) "client"
                                              (e-client-face)
                                              (e-server-face))))))))
  (defun clojure-highlight-db-ident-keyword ()
    (font-lock-add-keywords nil
                            '((":db/ident[[:space:]]+\\(:[^[:space:]\n]+\\)"
                               1 'clojure-db-ident-keyword-face prepend))))
  (defun clojure-add-electric-keywords ()
    (font-lock-add-keywords nil '((clojure-highlight-electric-blocks))))
  (add-to-list 'org-structure-template-alist '("clj" . "src clojure"))
  (add-to-list 'clojure-align-binding-forms "e/server")
  (add-to-list 'clojure-align-binding-forms "e/client")
  (add-to-list 'clojure-align-binding-forms "e/on-unmount")
  (put-clojure-indent 'e/defn :defn)
  (put-clojure-indent 'e/def :def)
  (put-clojure-indent 'compojure.core/DELETE :defn)
  (put-clojure-indent 'compojure.core/GET :defn)
  (put-clojure-indent 'compojure.core/POST :defn)
  (put-clojure-indent 'compojure.core/PUT :defn)
  (put-clojure-indent 'compojure.core/context :defn)
  (put-clojure-indent 'clojure.test.check.properties/for-all :defn)
  (setq clojure-ts-indent-style 'fixed
        clojure-indent-style 'always-indent
        clojure-indent-keyword-style 'always-indent
        clojure-enable-indent-specs nil
        clojure-align-forms-automatically t))

hkjels 2025-03-12T13:59:13.647969Z

Looks like nomis is doing quite a bit more

2025-03-12T14:13:36.014589Z

@hkjels Thanks for sharing!

👍 1
2025-03-11T15:26:05.740569Z

👀 1
2025-03-11T15:27:01.038189Z

Sometimes the background colours can get in the way, so this is a nice alternative.

2025-03-11T15:27:44.323529Z

It’s easy to switch between backgrounds and underlining.

2025-03-11T16:11:07.768359Z

I’ve just realised that this is all rather broken. For example the h and s on line 28 above shouldn’t be colored. I don’t think it’s easy to fix. Grrrr!

😢 1
2025-03-11T17:07:02.897819Z

just wanted to say this is a really cool project and i hope it works out!

2025-03-11T17:08:02.996759Z

Thanks. I may be able to fix it to an extent. Just trying something now.

braai engineer 2025-03-11T18:26:50.731569Z

Could Electric be used for syncing multiplayer Clojure code editors at the s-expr level, where S-exprs are like DOM tree? CRDT pain etc etc. i.e. Paredit-like point effects. Real motivation is LLM integration as you type to stream to model, and see its proposed edits without constantly diffing. But also, multiplayer Clojure 🙂

🤔 2
Dustin Getz (Hyperfiddle) 2025-03-11T21:48:46.382959Z

i think CRDT is the right structure for this, "conflict free" is what collaborative editors want (electric can still manage the network connection, the CRDT libs should support network-free usage)

braai engineer 2025-03-12T05:18:44.776209Z

Even if we ignored conflicts, I guess Electric would have to know the AST on both client and server ahead of time? Since writing code is modifying the AST, i.e. more analogous to compiler step than runtime, but then back to diffing or CRDTs.