Skip to content

Commit 2963f5d

Browse files
authored
Merge pull request #2104 from lem-project/feat/filer-git-status
feat(filer): add git status display integration
2 parents d5a703a + c77396e commit 2963f5d

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed

extensions/git-gutter/git-gutter.lisp

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@
271271
'git-gutter-on-change)
272272
;; Add directory-mode support
273273
(add-directory-mode-inserter)
274-
(update-all-directory-buffers))
274+
(update-all-directory-buffers)
275+
;; Add filer support
276+
(add-filer-inserter)
277+
(update-filer-buffer))
275278

276279
(defun disable-hook ()
277280
"Called when git-gutter-mode is disabled."
@@ -284,6 +287,9 @@
284287
(clear-all-buffers)
285288
;; Remove directory-mode support and clear cache
286289
(remove-directory-mode-inserter)
290+
;; Remove filer support
291+
(remove-filer-inserter)
292+
(update-filer-buffer)
287293
(clear-directory-status-cache))
288294

289295
(define-minor-mode git-gutter-mode
@@ -503,12 +509,56 @@
503509
"Clear the directory git status cache."
504510
(clrhash *directory-git-status-cache*))
505511

512+
;;; Filer Git Status Support
513+
514+
(defun insert-filer-git-status (point item root-directory)
515+
"Inserter function for filer to show git status."
516+
(let* ((pathname (lem/filer:item-pathname item))
517+
(status (when (and pathname root-directory)
518+
(get-file-git-status pathname root-directory))))
519+
(multiple-value-bind (char attr)
520+
(status-to-display status)
521+
(if attr
522+
(insert-string point (format nil "~A " char) :attribute attr)
523+
(insert-string point " ")))))
524+
525+
(defun add-filer-inserter ()
526+
"Add git status inserter to filer."
527+
(when (find-package :lem/filer)
528+
(let ((inserters (find-symbol "*FILER-ITEM-INSERTERS*" :lem/filer)))
529+
(when (and inserters (boundp inserters))
530+
(unless (member #'insert-filer-git-status (symbol-value inserters))
531+
(push #'insert-filer-git-status (symbol-value inserters)))))))
532+
533+
(defun remove-filer-inserter ()
534+
"Remove git status inserter from filer."
535+
(when (find-package :lem/filer)
536+
(let ((inserters (find-symbol "*FILER-ITEM-INSERTERS*" :lem/filer)))
537+
(when (and inserters (boundp inserters))
538+
(setf (symbol-value inserters)
539+
(remove #'insert-filer-git-status (symbol-value inserters)))))))
540+
541+
(defun update-filer-buffer ()
542+
"Update filer buffer to reflect git status changes."
543+
(when (find-package :lem/filer)
544+
(let ((filer-buffer-fn (find-symbol "FILER-BUFFER" :lem/filer))
545+
(root-item-fn (find-symbol "ROOT-ITEM" :lem/filer))
546+
(render-fn (find-symbol "RENDER" :lem/filer)))
547+
(when (and filer-buffer-fn (fboundp filer-buffer-fn)
548+
root-item-fn (fboundp root-item-fn)
549+
render-fn (fboundp render-fn))
550+
(alexandria:when-let ((buffer (funcall filer-buffer-fn)))
551+
(alexandria:when-let ((root (funcall root-item-fn buffer)))
552+
(funcall render-fn buffer root)))))))
553+
506554
(define-command git-gutter-refresh-directory-status () ()
507-
"Refresh git status cache for current directory buffer."
555+
"Refresh git status cache for current directory buffer and filer."
508556
(let ((directory (buffer-directory (current-buffer))))
509557
(when directory
510558
(remhash (namestring directory) *directory-git-status-cache*)
511559
;; Force redisplay of directory buffer if in directory-mode
512560
(when (eq (buffer-major-mode (current-buffer)) 'lem/directory-mode:directory-mode)
513561
(update-buffer (current-buffer)))
562+
;; Also update filer buffer
563+
(update-filer-buffer)
514564
(message "Git status refreshed"))))

extensions/git-gutter/tests/git-gutter-tests.lisp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,39 @@ D deleted.lisp")
370370
"Test parsing empty output"
371371
(let ((status (gutter:parse-git-diff-name-status "")))
372372
(ok (= (hash-table-count status) 0) "Empty output should have no entries")))
373+
374+
;;; Test filer integration functions
375+
376+
(deftest test-filer-inserter-functions-exist
377+
"Test that filer integration functions exist"
378+
(ok (fboundp 'lem-git-gutter::insert-filer-git-status)
379+
"insert-filer-git-status should be defined")
380+
(ok (fboundp 'lem-git-gutter::add-filer-inserter)
381+
"add-filer-inserter should be defined")
382+
(ok (fboundp 'lem-git-gutter::remove-filer-inserter)
383+
"remove-filer-inserter should be defined")
384+
(ok (fboundp 'lem-git-gutter::update-filer-buffer)
385+
"update-filer-buffer should be defined"))
386+
387+
(deftest test-filer-inserter-registration
388+
"Test that filer inserter can be added and removed"
389+
(when (find-package :lem/filer)
390+
(let* ((inserters-sym (find-symbol "*FILER-ITEM-INSERTERS*" :lem/filer))
391+
(original-value (when (and inserters-sym (boundp inserters-sym))
392+
(symbol-value inserters-sym))))
393+
(when (and inserters-sym (boundp inserters-sym))
394+
(unwind-protect
395+
(progn
396+
;; Clear and test add
397+
(setf (symbol-value inserters-sym) '())
398+
(lem-git-gutter::add-filer-inserter)
399+
(ok (member #'lem-git-gutter::insert-filer-git-status
400+
(symbol-value inserters-sym))
401+
"insert-filer-git-status should be in *filer-item-inserters*")
402+
;; Test remove
403+
(lem-git-gutter::remove-filer-inserter)
404+
(ok (not (member #'lem-git-gutter::insert-filer-git-status
405+
(symbol-value inserters-sym)))
406+
"insert-filer-git-status should be removed from *filer-item-inserters*"))
407+
;; Restore original value
408+
(setf (symbol-value inserters-sym) original-value))))))

src/ext/filer.lisp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,17 @@
99
:directory-item-open-p
1010
:directory-item-children
1111
:file-item
12-
:item-pathname))
12+
:item-pathname
13+
:*filer-item-inserters*
14+
:root-item
15+
:render
16+
:filer-buffer))
1317
(in-package :lem/filer)
1418

19+
(defparameter *filer-item-inserters* '()
20+
"List of functions to call before inserting filer items.
21+
Each function takes (point item root-directory) arguments.")
22+
1523
(define-attribute triangle-attribute
1624
(t :bold t :foreground :base0D))
1725

@@ -103,6 +111,11 @@
103111
(defun insert-item (point item)
104112
(with-point ((start point))
105113
(back-to-indentation start)
114+
;; Call registered inserters for pluggable extensions (e.g., git status)
115+
(let ((root-directory (alexandria:when-let ((root (root-item (point-buffer point))))
116+
(item-pathname root))))
117+
(dolist (inserter *filer-item-inserters*)
118+
(funcall inserter point item root-directory)))
106119
(lem/directory-mode/internal::insert-icon point (item-pathname item))
107120
(insert-string point
108121
(item-content item)

tests/filer.lisp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,27 @@
8080
(let ((root (create-directory-item #P"/tmp/")))
8181
(ng (expand-to-directory root #P"/var/")))))
8282

83+
;;; Test *filer-item-inserters*
84+
(deftest filer-item-inserters-test
85+
(testing "*filer-item-inserters* exists and is initially empty"
86+
(ok (boundp 'lem/filer:*filer-item-inserters*))
87+
(ok (listp lem/filer:*filer-item-inserters*)))
88+
89+
(testing "inserters can be added and removed"
90+
(let ((original-value lem/filer:*filer-item-inserters*))
91+
(unwind-protect
92+
(let ((test-inserter (lambda (point item root-directory)
93+
(declare (ignore point item root-directory)))))
94+
;; Add inserter
95+
(push test-inserter lem/filer:*filer-item-inserters*)
96+
(ok (member test-inserter lem/filer:*filer-item-inserters*))
97+
;; Remove inserter
98+
(setf lem/filer:*filer-item-inserters*
99+
(remove test-inserter lem/filer:*filer-item-inserters*))
100+
(ok (not (member test-inserter lem/filer:*filer-item-inserters*))))
101+
;; Restore original value
102+
(setf lem/filer:*filer-item-inserters* original-value)))))
103+
83104
;;; Note: Tests for filer-active-p, filer-buffer, filer-current-directory,
84105
;;; and highlight-file-in-filer are not included here because they require
85106
;;; a full editor environment with *implementation* bound.

0 commit comments

Comments
 (0)