Clojurescript: How to destructure a js-object in an idiomatic way - clojurescript

Trying to use antd from clojurescript I'm looking for an idiomatic way to destructure js-objects. So assume we want to do e.g.
import { Layout } from 'antd';
const { Header, Footer, Sider, Content } = Layout;
How can I do that from clojurescript without having to write the verbose
(let [Sider (.-Sider antd/Layout)
Header (.-Header antd/Layout)
Content (.-Content antd/Layout)
Footer (.-Footer antd/Layout)]
;; and here goes the hiccup using Sider etc.
)
thanks in advance
fricke

The useful forms of destructuring (:keys, :strs) won't work because a regular JS object is not a CLJS map. Maybe you can create an util function around aget and use regular positional destructuring?
(defn obj-props [obj props]
(map #(aget obj (name %)) props))
(let [[Sider Header Content Footer] (obj-props antd/Layout '[Sider Header Content Footer])]
;; Sider, Header, etc. are bound here
)
I found a recommendation on the Cljs Cheat Sheet of the cljs-oops library, which in turn mentioned aget, and the aget docs mentioned goog.object/get 😉

Here's how i currently prefer to do it:
(let [[Sider Header Content Footer]
(as-> antd/Layout $ [(.-Sider $) (.-Header $) (.-Content $) (.-Footer $)])]
;; and here goes the hiccup using Sider etc.
)
Or else:
(let [[Sider Header Content Footer]
((juxt #(.-Sider %) #(.-Header %) #(.-Content %) #(.-Footer %)) antd/Layout)]
;; and here goes the hiccup using Sider etc.
)

Related

Render html to racket gui

I'm trying to write a WYSIWYG text editor that allows me to write text in the top window, and have the resulting scribble text rendered in the bottom window. I figured the way I would do this would be to call scribble myfile.rkt in the background periodically, and then render the resulting output to a bottom screen using render-html-to-text. I'm having some trouble getting the render to work. Based on the documentation I need
in : input-port?
dest : (is-a? html-text<%>)
load-img? : any/c
eval-rkt? : any/c
The relevant parts of my script look like this
#lang racket/gui
(require racket/os racket/runtime-path "init.rkt"
browser/htmltext)
(require browser)
(define f (new frame% [label (~a "Dremacs" "#" (gethostname))]
[width 960]
[height 540]))
(define new-cnv (new cnv% [parent f]))
(send t insert ";; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with C-x C-f and enter text in its buffer.")
(send new-cnv set-editor t)
(define html-renderer%
(interface (html-text<%>)))
(define viewer (new panel%
[parent f]
[min-width 300]
[min-height 300]))
(render-html-to-text (open-input-file "TODO.html") html-renderer% #t #t)
(send f show #t)
But I get the error
render-html-to-text: expects argument of type <html-text<%> object>; given: '(#<input-port:/home/diego/repos/dremacs/dremacs/TODO.html> #<interface:html-renderer%>)
context...:
/usr/share/racket/pkgs/drracket/browser/htmltext.rkt:61:0: render-html-to-text
"/home/diego/repos/dremacs/dremacs/editor.rkt": [running body]
temp37_0
And I'm not sure what I'm doing wrong. Could anyone help?
The html-renderer% is not created correctly.
Use html-text-mixin to turn a text% into something that handles html-text.
But ... don't expect too much from the html-renderer.
It's old and doesn't support stylesheets.
Back in the day it was used to display documentation for DrRacket.

"Autosave" Functionality in ClojureScript

I'd like to add an "autosave" feature to a Reagent form in a ClojureScript function. In Clojure, I usually make something out of a ScheduledExecutorService. Since that isn't available in ClojureScript, I came up with the following.
(def delay-handle (atom nil))
(defn clear-autosave-delay! []
(.clearTimeout js/window #delay-handle))
(defn start-autosave-delay!
[doc-save-fn delay-ms page-map-atom]
(reset! delay-handle (.setTimeout js/window doc-save-fn delay-ms page-map-atom)))
(defn change-watcher!
[doc-save-fn page-map-atom]
(let [delay (* 1000 (get-in #page-map-atom [:options :editor_autosave_interval]))]
(when (pos? delay)
(clear-autosave-delay!)
(start-autosave-delay! doc-save-fn delay page-map-atom))))
I put the change-watcher! function in the Reagent :on-change handlers for the input controls. Whenever a change occurs, it resets the delay. If the delay expires, the doc-save-fn is called to do the save.
It seems to work Ok, but isn't very "Clojuresque." Is there a more idiomatic way to write this?​
Use debouncer for this issue. It's pretty simple and does same
(goog.functions.debounce auto-save-action 1000)

Dynamically Create AutoHotkey Hotkey to Function/Subroutine

The AutoHotkey command Hotkey allows for the creation of dynamic hotkeys at runtime, but its syntax and documentation seems to limit it to built-in or existing labels/subroutines, which makes it much less useful:
Hotkey, KeyName [, Label, Options]
Is there a way to get it to work like regular, hard-coded hotkeys? For example:
#z::MsgBox foobar ; Typical, hard-coded hotkey pops up a message-box
Hotkey, z, MsgBox foobar ; Nope; complains about missing label “MsgBox foobar”
It looks like it might be possible due to the following line from the manual, however it is not clear how it would work:
Label - Both normal labels and hotkey/hotstring labels can be used.
This is a refinement of FakeRainBrigand's answer. It is used exactly the same:
Hotkey("x", "Foo", "Bar") ; this defines: x:: Foo("Bar")
Changes from the original:
Prevent accidental auto-execute of the handler subroutine by tucking it into the function.
Allowing me to reduce namespace pollution by narrowing the scope of the hotkeys variable from global to static.
Optimizations: fun is looked up only once (using Func()) at hotkey definition time; At invocation time, object lookups reduced four to two by splitting hotkeys into two objects funs and args;
This still relies of course on the _L version of AutoHotKey because of Object notation and variadic arg* syntax.
Hotkey(hk, fun, arg*) {
Static funs := {}, args := {}
funs[hk] := Func(fun), args[hk] := arg
Hotkey, %hk%, Hotkey_Handle
Return
Hotkey_Handle:
funs[A_ThisHotkey].(args[A_ThisHotkey]*)
Return
}
Doing exactly what you want isn't possible in AutoHotkey. This is the closest way I can think of.
Call this file Hotkeys.ahk, and put it in My Documents/AutoHotkey/Lib. Alternatively make a folder called Lib, and put it in the same directory as your main script.
Hotkeys := {}
Hotkey(hk, fun, p*) {
global hotkeys
hotkeys[hk] := {}
hotkeys[hk].fun := fun
hotkeys[hk].p := p
Hotkey, %hk%, HandleHotkey
}
HandleHotkey:
hotkeys[A_ThisHotkey].fun(hotkeys[A_ThisHotkey].p*)
return
Here's an example script that you could use it with.
Hotkey("e", "msgbox", "foobar")
MsgBox(msg) {
msgbox % msg
}
#Include <Hotkeys>
The first parameter is the hotkey, the second is the function to call, and everything after that is passed to the function.
Is this what you are looking for?
#Persistent
#SingleInstance Force
#installKeybdHook
Hotkey, #z, MyLabel
MyLabel:
MsgBox,OK
Return
With newer ahk version you can now use functions as label argument. See https://www.autohotkey.com/docs/commands/Hotkey.htm

Emacs: Universal argument (C-u) in a function

I would like to use C-u in a function (for instance, regexp) where calling it with C-u has a different effect. How can I do this in Emacs? The documentation doesn't show how to do this with Emacs Lisp.
(defun test ()
(interactive)
(align-regexp)) ; I would like to add the C-u prefix to this.
(defun my/test ()
(interactive)
(let ((current-prefix-arg 4)) ;; emulate C-u
(call-interactively 'align-regexp) ;; invoke align-regexp interactively
)
)
Hope that helps.
I arrived here looking for a way to detect if my function had been called with C-u. This is how you do it:
(defun my-function ()
(interactive)
(if (equal current-prefix-arg nil) ; no C-u
;; then
(message "my-function was called normally")
;; else
(message "my-function was called with C-u")))
What the original poster was asking is how to call another function with C-u, from inside his/her function.
I post this as a clarification to #codyChan's comment above, in the hope that it might help others.

Image Processing, extending JPanel and Simulating Classes in Clojure

there! I'm building an image-processing application in swing/clojure, and right now I need to develop an image panel in which I can click and compute data. Thanks to coobird, I now have a good idea on how to do it in Java, but I still don't get many issues on its integration with Clojure.
Let's take a look at how coobird suggested me doing. First, we should extend a class in Java. In clojure, we do this with the proxy macro, so we'd have something like this:
(def painting-panel
(proxy [JPanel] []))
The next step is to create the class constructor and set some variables.
I can define functions after the second argument of proxy, but how can I create the constructor? Is painting-panel the name of this class (therefore the name of the function I should create)?
How can I deal with class variables? Should I define them with a let, like I did?
Are this and super available for me to use, like I did below?
(def painting-panel
(let [background-image (Image.)
point-clicked (Point.)]
(proxy [JPanel] []
(paintComponent [g]
(do ((.paintComponent super) g)
(doto g
(.drawImage background-image 0 0 nil)
(.fillRect (.x point-clicked) (.y point-clicked) 1 1))))
(painting-panel []; constructor?
((.addMouseListener this)
(proxy [MouseAdapter] []
(mouseClicked [e]
(do
(def point-clicked (.getPoint e))
(.repaint this)))))))))
Suggestions and code corrections are also welcome!
Thank you!
proxy actually creates an instance tada! You don't need to create a constructor.
Yes, but consider using a clojure ref instead. Also using def like that on the second last line is nasty! it creates a global binding for point-clicked when your logic relies on the lexically scoped one created by let.
(proxy-super paintComponent g), and yes "this" is available
This works for me:
(let [click (ref nil)
panel (proxy [javax.swing.JPanel] []
(paintComponent [g]
(proxy-super paintComponent g)
(.drawImage g (.getImage
(javax.swing.ImageIcon. "play.png"))
0 0 (.getWidth this) (.getHeight this) nil)
(if #click
(.fillRect g (:x #click) (:y #click) 10 10))))]
(.addMouseListener panel
(proxy [java.awt.event.MouseAdapter] []
(mouseClicked [e]
(let [p (.getPoint e)]
(dosync (ref-set click {:x (.x p), :y (.y p)})))
(javax.swing.SwingUtilities/invokeLater #(.repaint panel)))))
(doto (javax.swing.JFrame.)
(.setContentPane panel)
(.setSize 200 200)
(.show)))