Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
36fb4a4
support for invisibility and "virtual" items
mahmoodsh36 Jun 16, 2026
535ef07
make previous-line/next-line skip hidden lines
mahmoodsh36 Jun 18, 2026
ec41797
add generic defun-folding and bind it to tab
mahmoodsh36 Jun 19, 2026
8570dbb
improve invisiblity behavior
mahmoodsh36 Jun 27, 2026
548b77e
add test
mahmoodsh36 Jun 27, 2026
3b67950
make overlay enter/exit behavior customizable
mahmoodsh36 Jun 30, 2026
46c4573
fold only when on first line of defun
mahmoodsh36 Jul 1, 2026
0a78684
fix scrolling issue
mahmoodsh36 Jul 3, 2026
039b7dd
support for displaying images in webview
mahmoodsh36 Jul 4, 2026
580e511
evict drawing-cache entries a tall line overlaps
mahmoodsh36 Jul 28, 2026
6f09e2d
drop the fingerprint entries of the rows a tall line covers
mahmoodsh36 Jul 28, 2026
e4e19a8
rename lem-if:get-char-width/height to cell-width/cell-height
mahmoodsh36 Jul 31, 2026
3d2ea17
move default object-width/object-height into the core
mahmoodsh36 Jul 31, 2026
d0c48e6
lay rows out in the core, hand frontends a laid-out row
mahmoodsh36 Jul 31, 2026
f98c6e7
draw the webview frontend in pixels
mahmoodsh36 Aug 1, 2026
a9bfe67
let an image sit on the baseline and be cropped at the edge
mahmoodsh36 Aug 1, 2026
40db435
let virtual text contain newlines
mahmoodsh36 Aug 1, 2026
a136112
hit test the mouse against the rows actually drawn
mahmoodsh36 Aug 1, 2026
eb9778a
fill a row with draw-block instead of a textless put
mahmoodsh36 Aug 2, 2026
5c33e40
give object-width's cache a slot of its own
mahmoodsh36 Aug 3, 2026
71141f9
turn a click into a column by walking the objects drawn
mahmoodsh36 Aug 3, 2026
003a966
highlight a row as tall as the image on it
mahmoodsh36 Aug 3, 2026
a58735a
let frontends report the font's em size
mahmoodsh36 Aug 3, 2026
064758b
fix theme colors not reaching get-foreground-color/get-background-color
mahmoodsh36 Aug 4, 2026
7a50d2a
let virtual text carry an attribute per run
mahmoodsh36 Aug 4, 2026
b76d8fa
add image-support-p field to frontend definitions
mahmoodsh36 Aug 10, 2026
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 .claude/rules/frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Frontends subclass `implementation` and implement `lem-if:*` generics.
(lem-if:set-view-pos impl view x y)

;; Rendering
(lem-if:render-line impl view x y objects height)
(lem-if:render-row impl view row) ; ROW is a laid-out lem-core/display:row
(lem-if:clear-to-end-of-window impl view y)
```

Expand Down
12 changes: 6 additions & 6 deletions extensions/pixel-demo/pixel-demo.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
(defun animation-step ()
"Perform one animation step."
(when (and *demo-window* (eq *demo-mode* :animate))
(let* ((char-width (lem-if:get-char-width (implementation)))
(char-height (lem-if:get-char-height (implementation)))
(let* ((char-width (lem-if:cell-width (implementation)))
(char-height (lem-if:cell-height (implementation)))
(display-width (* (display-width) char-width))
(display-height (* (display-height) char-height))
(win-width (or (floating-window-pixel-width *demo-window*)
Expand Down Expand Up @@ -177,8 +177,8 @@ A floating window follows your mouse cursor at pixel precision."
"Update coordinate debug display."
(when (and *demo-window* (eq *demo-mode* :debug))
(let* ((mouse-event (lem-core::last-mouse-event))
(char-width (lem-if:get-char-width (implementation)))
(char-height (lem-if:get-char-height (implementation))))
(char-width (lem-if:cell-width (implementation)))
(char-height (lem-if:cell-height (implementation))))
(multiple-value-bind (win-px win-py win-pw win-ph)
(floating-window-pixel-bounds *demo-window*)
(let ((content
Expand Down Expand Up @@ -230,8 +230,8 @@ Shows real-time pixel and character coordinate information."
(defun compare-animation-step ()
"Animate both windows for comparison."
(when (eq *demo-mode* :compare)
(let* ((char-width (lem-if:get-char-width (implementation)))
(char-height (lem-if:get-char-height (implementation)))
(let* ((char-width (lem-if:cell-width (implementation)))
(char-height (lem-if:cell-height (implementation)))
(display-width (* (display-width) char-width))
(display-height (* (display-height) char-height))
(win-width (* 20 char-width)))
Expand Down
19 changes: 11 additions & 8 deletions extensions/vi-mode/commands.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -198,16 +198,19 @@

(define-command vi-forward-char (&optional (n 1)) (:universal)
(let* ((p (current-point))
(max-offset (- (length (line-string p))
(point-charpos p))))
(max-offset (with-point ((e p))
(visual-line-end e)
(count-characters p e))))
(character-offset p (min n max-offset))))

(define-command vi-backward-char (&optional (n 1)) (:universal)
(let ((p (current-point)))
(dotimes (_ n)
(if (bolp p)
(return)
(character-offset p -1)))))
(with-point ((bol p))
(visual-line-beginning bol)
(dotimes (_ n)
(if (point<= p bol)
(return)
(character-offset p -1))))))

(define-motion vi-next-line (&optional (n 1)) (:universal)
(:type :line)
Expand Down Expand Up @@ -309,7 +312,7 @@

(define-command vi-move-to-beginning-of-line () ()
(with-point ((start (current-point)))
(line-start start)
(visual-line-beginning start)
(or (text-property-at (current-point) :field -1)
(previous-single-property-change (current-point)
:field
Expand All @@ -318,7 +321,7 @@

(define-command vi-move-to-end-of-line (&optional (n 1)) (:universal)
(vi-line n)
(line-end (current-point)))
(visual-line-end (current-point)))

(define-command vi-move-to-last-nonblank () ()
(vi-move-to-end-of-line)
Expand Down
5 changes: 4 additions & 1 deletion extensions/vi-mode/commands/utils.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@
(1- len)))))

(defun fall-within-line (point)
(when (eolp point)
"clamps the given point to the character before the newline at the end of the line its in."
;; a buffer-line end whose newline is hidden by a fold is mid-visual-line, so we dont clamp.
(when (and (eolp point)
(not (invisible-overlay-covering point)))
(line-end point)
(unless (bolp point)
(character-offset point *cursor-offset*))))
Expand Down
16 changes: 7 additions & 9 deletions frontends/fake-interface/fake-interface.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,22 @@
(defmethod lem-if:object-height ((implementation fake-interface) object)
1)

(defmethod lem-if:render-line ((implementation fake-interface) view x y objects height)
(defmethod lem-if:render-row ((implementation fake-interface) view row)
nil)

(defmethod lem-if:clear-to-end-of-window ((implementation fake-interface) view y)
nil)

(defmethod lem-if:get-char-width ((implementation fake-interface))
(defmethod lem-if:cell-width ((implementation fake-interface))
1)

(defmethod lem-if:get-char-height ((implementation fake-interface))
(defmethod lem-if:cell-height ((implementation fake-interface))
1)

(defmethod lem-if:render-line-on-modeline ((implementation fake-interface)
view
left-objects
right-objects
default-attribute
height)
(defmethod lem-if:render-modeline-row ((implementation fake-interface)
view
row
default-attribute)
nil)

(defmacro with-fake-interface (() &body body)
Expand Down
29 changes: 0 additions & 29 deletions frontends/ncurses/drawing-object.lisp

This file was deleted.

1 change: 0 additions & 1 deletion frontends/ncurses/lem-ncurses.asd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
(:file "style")
(:file "key")
(:file "attribute")
(:file "drawing-object")
(:file "view")
(:file "render")
(:file "input")
Expand Down
33 changes: 18 additions & 15 deletions frontends/ncurses/ncurses.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,31 @@
(defmethod lem-if:view-height ((implementation ncurses) view)
(lem-ncurses/view:view-height view))

(defmethod lem-if:render-line ((implementation ncurses)
view x y objects height)
(lem-ncurses/render:render-line view x y objects))
(defmethod lem-if:render-row ((implementation ncurses) view row)
(lem-ncurses/render:render-row view row))

(defmethod lem-if:render-line-on-modeline ((implementation ncurses)
view
left-objects
right-objects
default-attribute
height)
(lem-ncurses/render:render-line-on-modeline view left-objects right-objects default-attribute))
(defmethod lem-if:render-modeline-row ((implementation ncurses) view row default-attribute)
(lem-ncurses/render:render-modeline-row view row default-attribute))

(defmethod lem-if:object-width ((implementation ncurses) drawing-object)
(lem-ncurses/drawing-object:object-width drawing-object))
(defmethod lem-if:object-width ((implementation ncurses)
(drawing-object lem-core/display:image-object))
0)

(defmethod lem-if:object-height ((implementation ncurses) drawing-object)
(lem-ncurses/drawing-object:object-height drawing-object))
(defmethod lem-if:object-height ((implementation ncurses)
(drawing-object lem-core/display:image-object))
1)

(defmethod lem-if:object-ascent ((implementation ncurses)
(drawing-object lem-core/display:image-object))
1)

(defmethod lem-if:clear-to-end-of-window ((implementation ncurses) view y)
(lem-ncurses/render:clear-to-end-of-window view y))

(defmethod lem-if:get-char-width ((implementation ncurses))
(defmethod lem-if:cell-width ((implementation ncurses))
1)

(defmethod lem-if:cell-height ((implementation ncurses))
1)

;; for mouse control
Expand Down
64 changes: 28 additions & 36 deletions frontends/ncurses/render.lisp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(defpackage :lem-ncurses/render
(:use :cl
:lem-core/display)
(:export :render-line
:render-line-on-modeline
(:export :render-row
:render-modeline-row
:clear-to-end-of-window))
(in-package :lem-ncurses/render)

Expand Down Expand Up @@ -37,17 +37,6 @@
" "
(lem:make-attribute :foreground (lem:color-to-hex-string (eol-cursor-object-color object)))))

(defmethod draw-object ((object extend-to-eol-object) x y view scrwin)
(let ((width (lem-if:view-width (lem:implementation) view)))
(when (< x width)
(print-string
scrwin
x
y
(make-string (- width x) :initial-element #\space)
(lem:make-attribute :background
(lem:color-to-hex-string (extend-to-eol-object-color object)))))))

(defmethod draw-object ((object line-end-object) x y view scrwin)
(let ((string (text-object-string object))
(attribute (text-object-attribute object)))
Expand All @@ -61,40 +50,43 @@
(defmethod draw-object ((object image-object) x y view scrwin)
(values))

(defun render-line-from-behind (view y objects scrwin)
(loop :with current-x := (lem-if:view-width (lem:implementation) view)
:for object :in objects
:do (decf current-x (lem-ncurses/drawing-object:object-width object))
(draw-object object current-x y view scrwin)))

(defun clear-line (view x y)
(charms/ll:wmove (lem-ncurses/view:view-scrwin view) y x)
(charms/ll:wclrtoeol (lem-ncurses/view:view-scrwin view)))

(defun %render-line (view x y objects scrwin)
(loop :for object :in objects
:do (draw-object object x y view scrwin)
(incf x (lem-ncurses/drawing-object:object-width object))))
(defun draw-row (view row scrwin)
"Draw ROW's background fill, then everything placed on it.
The fill is spaces carrying the background color, since a terminal cell only takes a color by
having a character written into it."
(let ((width (lem-if:view-width (lem:implementation) view)))
(when (and (row-fill-color row)
(< (row-fill-x row) width))
(print-string scrwin
(row-fill-x row)
(row-top row)
(make-string (- width (row-fill-x row)) :initial-element #\space)
(lem:make-attribute :background
(lem:color-to-hex-string (row-fill-color row))))))
(loop :for placement :in (row-placements row)
:do (draw-object (placement-object placement)
(placement-x placement)
(placement-top placement)
view
scrwin)))

(defun render-line (view x y objects)
(clear-line view x y)
(%render-line view x y objects (lem-ncurses/view:view-scrwin view)))
(defun render-row (view row)
(clear-line view 0 (row-top row))
(draw-row view row (lem-ncurses/view:view-scrwin view)))

(defun render-line-on-modeline (view
left-objects
right-objects
default-attribute)
(defun render-modeline-row (view row default-attribute)
;; the modeline gets its own curses window, so its row (laid out at top 0) needs no translation.
(print-string (lem-ncurses/view:view-modeline-scrwin view)
0
0
(row-top row)
(make-string (lem-ncurses/view:view-width view)
:initial-element #\space)
default-attribute)
(%render-line view 0 0 left-objects (lem-ncurses/view:view-modeline-scrwin view))
(render-line-from-behind view
0
right-objects
(lem-ncurses/view:view-modeline-scrwin view)))
(draw-row view row (lem-ncurses/view:view-modeline-scrwin view)))

(defun clear-to-end-of-window (view y)
(let ((win (lem-ncurses/view:view-scrwin view)))
Expand Down
4 changes: 2 additions & 2 deletions frontends/ncurses/view.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
:set-view-pos
:redraw-view-after
:redraw-display-after
:render-line
:render-line-on-modeline
:render-row
:render-modeline-row
:clear-to-end-of-window
:update-display
:set-last-print-cursor))
Expand Down
2 changes: 1 addition & 1 deletion frontends/sdl2/display.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Retina to a 1x display).")
:documentation
"Pre-allocated SDL_Rect reused across all render calls to
avoid heap-allocating a new rect + Lisp wrapper on every draw-rect,
fill-to-end-of-line, render-texture, etc. Mutated in-place by
fill-row, render-texture, etc. Mutated in-place by
`call-with-scratch-rect' / `with-scratch-rect'; do not rely on its
contents outside the dynamic extent of that call.")))

Expand Down
Loading
Loading