4545 :type 'hook
4646 :group 'eca )
4747
48- (defface eca-rewrite-highlight -face
48+ (defface eca-rewrite-overlay -face
4949 '((((class color ) (min-colors 88 ) (background dark ))
5050 :background " #041117" :extend t )
5151 (((class color ) (min-colors 88 ) (background light ))
5454 " Face to highlight pending rewrite regions."
5555 :group 'eca )
5656
57+ (defface eca-rewrite-overlay-hover-face
58+ '((t (:inherit eca-rewrite-overlay-face :weight semi-bold)))
59+ " Face used for rewrite overlay content when point is inside it."
60+ :group 'eca )
61+
5762(defface eca-rewrite-in-progress-prefix-face
5863 '((t (:inherit shadow )))
5964 " Face to show in the in progress prefix text."
7984(defvar-local eca-rewrite--overlays nil
8085 " Active rewrite overlays in this buffer." )
8186
87+ (defvar-local eca-rewrite--hovered-ov nil
88+ " Currently hovered rewrite overlay (point inside), or nil." )
89+
8290(defvar-keymap eca-rewrite-actions-map
8391 :doc " Keymap for rewrite overlay actions."
8492 " a" #'eca-rewrite-accept
@@ -121,6 +129,41 @@ LABEL is the base text prefix."
121129 (propertize " " 'display `(space :align-to (- right ,(1+ (length model-str)))))
122130 (propertize model-str 'face 'eca-rewrite-model-face ))))
123131
132+ (defun eca-rewrite--apply-display-face (ov face )
133+ " Apply FACE to OV's display string, preserving syntax faces.
134+ If the overlay is currently hidden (no display), do nothing."
135+ (when (and (overlay-get ov 'display )
136+ (overlay-get ov 'eca-rewrite--display-base ))
137+ (let* ((base (overlay-get ov 'eca-rewrite--display-base ))
138+ (disp (copy-sequence base)))
139+ (add-face-text-property 0 (length disp) face 'append disp)
140+ (overlay-put ov 'display disp))))
141+
142+ (defun eca-rewrite--apply-normal-face (ov )
143+ " Restore normal highlight face to OV."
144+ (if (overlay-get ov 'eca-rewrite--display-base )
145+ (eca-rewrite--apply-display-face ov 'eca-rewrite-overlay-face )
146+ (overlay-put ov 'face 'eca-rewrite-overlay-face )))
147+
148+ (defun eca-rewrite--apply-hover-face (ov )
149+ " Apply hover face to OV."
150+ (if (overlay-get ov 'eca-rewrite--display-base )
151+ (eca-rewrite--apply-display-face ov 'eca-rewrite-overlay-hover-face )
152+ (overlay-put ov 'face 'eca-rewrite-overlay-hover-face )))
153+
154+ (defun eca-rewrite--hover-update ()
155+ " Update hover styling based on point location."
156+ (let ((current-ov (eca-rewrite--overlay-at-point)))
157+ (unless (eq current-ov eca-rewrite--hovered-ov)
158+ ; ; Remove hover face from previous overlay
159+ (when (overlayp eca-rewrite--hovered-ov)
160+ (eca-rewrite--apply-normal-face eca-rewrite--hovered-ov))
161+ ; ; Update hovered overlay reference
162+ (setq eca-rewrite--hovered-ov current-ov)
163+ ; ; Apply hover face to the new overlay, if present
164+ (when (overlayp current-ov)
165+ (eca-rewrite--apply-hover-face current-ov)))))
166+
124167(defun eca-rewrite--setup-overlay (id start end text path prompt model )
125168 " Create an overlay for ID from START to END.
126169TEXT is the original selected text
@@ -138,14 +181,15 @@ MODEL is the LLM model used."
138181 (overlay-put ov 'eca-rewrite--path path)
139182 (overlay-put ov 'eca-rewrite--prompt prompt)
140183 (overlay-put ov 'eca-rewrite--model model)
141- (overlay-put ov 'face 'eca-rewrite-highlight -face )
184+ (overlay-put ov 'face 'eca-rewrite-overlay -face )
142185 (overlay-put ov 'priority 2000 )
143186 (overlay-put ov 'keymap eca-rewrite-actions-map)
144187 (overlay-put ov 'help-echo " ECA rewrite" )
145188 (overlay-put ov 'before-string (eca-rewrite--overlay-menu-str
146189 ov
147190 (propertize " Requesting LLM..." 'face 'eca-rewrite-in-progress-prefix-face )))
148191 (push ov eca-rewrite--overlays)
192+ (add-hook 'post-command-hook #'eca-rewrite--hover-update nil t )
149193 ov))
150194
151195(defun eca-rewrite--show-overlay-actions (ov )
@@ -173,7 +217,12 @@ overlay, remove it from the internal tracking list
173217No confirmation is asked; a nil OVS is ignored. Returns nil."
174218 (dolist (ov (ensure-list ovs))
175219 (setq eca-rewrite--overlays (delq ov eca-rewrite--overlays))
176- (delete-overlay ov)))
220+ (when (eq ov eca-rewrite--hovered-ov)
221+ (setq eca-rewrite--hovered-ov nil ))
222+ (delete-overlay ov))
223+ (when (null eca-rewrite--overlays)
224+ (remove-hook 'post-command-hook #'eca-rewrite--hover-update t )
225+ (setq eca-rewrite--hovered-ov nil )))
177226
178227(defun eca-rewrite--accept (ov )
179228 " Accept rewrite overlay OV."
@@ -367,7 +416,12 @@ so shorter rewrites don't leave leftover original text in the overlay."
367416 ; ; Move the highlight to the display string so show-paren-mode
368417 ; ; overlays on buffer text don't repaint the whole overlay.
369418 (let ((disp (copy-sequence propertized)))
370- (overlay-put ov 'display disp))))))
419+ ; ; Keep a base version (syntax faces only) to compose with our faces.
420+ (overlay-put ov 'eca-rewrite--display-base disp)
421+ ; ; Initial (non-hover) display uses the normal highlight face.
422+ (let ((initial (copy-sequence disp)))
423+ (add-face-text-property 0 (length initial) 'eca-rewrite-overlay-face 'append initial)
424+ (overlay-put ov 'display initial)))))))
371425
372426; ; Public
373427
0 commit comments