Aim to streamline the process of building model interactive flex layout app that resemble the react development experience.
Assume you already have rust installed.
git clone https://github.com/knilink/reed.el.git
cd reed.el
cargo build --releaseIf success, libreed.so should be generated at target/release/libreed.so
Create a file my-first-app.el with the following content
;; -*- lexical-binding: t -*-
(require 'reed-elx)
(require 'reed-hooks)
(require 'reed-style)
(require 'reed-render-helper)
(fc! Container (children)
(elx!
(div
:style (style!*
(size (width . 100%) (height . AUTO))
(flex_direction . 'Column)
(align_items . '(Center)))
({} children))))
(fc! Row (children)
(elx!
(div
:style (style!*
(justify_content . '(Center))
(size (width . 100%) (height . AUTO)))
({} children))))
(fc! App ()
(let ((current-time-sig (use-signal (lambda () (current-time-string))))
(buffer-name-ref (use-ref (lambda () (buffer-name)))))
(use-hook-with-cleanup
(lambda ()
(run-with-timer
0 1
(lambda ()
(funcall current-time-sig (current-time-string))
(reed-handle-render (funcall buffer-name-ref)))))
(lambda (timer-handle) (cancel-timer timer-handle)))
(elx!
(Container
(Row (p (span
:face '(:foreground "red" :background "yellow")
"Hello, ")
(span
:face '(:foreground "green" :background "blue")
"World!")))
(Row (p "Time is now: " ({} (funcall current-time-sig))))))))
(reed-render-buffer "my-first-app" #'App)Then run the app with
emacs -l reed.el/target/release/libreed.so -L reed.el/lisp -l ./my-first-app.el -QIf everything goes well, result bellow can be seen.

- oh-puhn-text-ui.el: A more interactive text ui llm frontend.
-
divThe fundamental layout container. Used for structuring UI components with flexible styling options. -
p(Paragraph) Text container that serves as a leaf node in the layout hierarchy.- Children can only be
spanelements - Primarily used for text content with styling
- Children can only be
-
spanInline text styling element.- Only valid as a child of
pelements - Supports only the
faceproperty for text styling - Used for applying different styles to portions of text
- Only valid as a child of
-
styleS-expressions serialized taffy layout Style. -
faceFace text property for styling text. -
refProvides a way to obtain element id, subsequently can be use to retrieve element position etc. A ref is created withuse-refhook.
Event listeners will be triggered accordingly depends on event type and position attribute, event payload will be forwarded directly to listeners.
onclick: Triggered when cursor eventclickis emitted and the position is inside the target element.onfocus: Triggered when click inside an element while the target element isn't focused.onblur: Triggered when click outside an element while the target element is focused.onhover: Triggered when cursormoveis emitted and the position is inside the target element.onleave: Triggered when cursormoveis emitted and the position is outside the target element.
To emit a cursor event:
(reed-handle-cursor-event my-registered-app-name 'click my-event-position my-event-payload)
(reed-handle-cursor-event "my-first-app" 'move 123 '(:position 123))Provides a convenient way to create react element.
Tag starts with lower case will be treated as a native element tag otherwise a component.
Syntax: (elx! (tag ,@attr-plist ,@children) (Component ,@props-plist ,@children) &rest)
The body of {} will be treated as dynamic content and evaluated during runtime.
For example,
(elx! (div ({} (if flag (elx! (p "true")) "false"))))is equivalent to
<div>{flag ? <p>true</p> : "false"}</div>Used to define reusable React-like components that returns a element, use keyword symbol to define alias Example:
(fc! MyComponent (foo :bar bar-alias)
(message "[bar-alias] %s" bar-alias)
(elx! ...))
(elx! (MyComponent :foo "foo-value" :bar "bar-value"))
S-expressions serialized taffy layout Style.
To create the 4 different type of serialized length attribute, use reed-taffy-length.
- percent:
(reed-taffy-length 'percent 0.5) - length:
(reed-taffy-length 'length 80.0) - auto:
(reed-taffy-length 'auto 0.0) - zero:
(reed-taffy-length 'zero 0.0)
When specifying attribute declared as Optional in rust, e.g. justify_content: Option<JustifyContent>. The value need to be wrapped with brackets () to represent Some(attr), e.g. (justify_content . '(Center)).
Helper to compose style property, main to help expanding short handed length. Length value needs to be ended either pt or %, e.g.
(style!
(margin
(left . 100pt)
(right . 20%)
(top . ZERO)
(bottom . AUTO)))Same as style! but style will be expanded into static string during macro expansion. Recommended if style is static throughout the entire component lifetime.
(fc! App ()
(let ((count-sig (use-signal (lambda() 0))))
(elx!
(p
"Count: "
({} (funcall count-sig)))
(p " ")
(p
:face '(:background "gray80" :box (:line-width 1 :style released-button))
:onclick (lambda (e)
(funcall count-sig (1+ (funcall count-sig))))
"click me!"))))
(fc! App ()
(let ((element-ref (use-ref (lambda())))
(location-sig (use-signal (lambda())))
(buffer-name-ref (use-ref (lambda () (buffer-name)))))
(use-effect
(lambda ()
(run-with-timer
0 nil
(lambda ()
(unless (funcall location-sig)
(funcall
location-sig
(reed-get-absolut-location
(funcall buffer-name-ref)
(funcall element-ref)))
(reed-handle-render (funcall buffer-name-ref)))))))
(elx!
(div
:style (style!*
(padding (left . ZERO) (right . ZERO) (top . 10pt) (bottom . ZERO))
(justify_content . '(Center))
(size (width . 100%) (height . AUTO)))
(p
:ref element-ref
({} (format "this element located at %s" (funcall location-sig))))))))