Reputation: 2465
The existing question How to have objects print nicely in Guile scheme repl focuses on customizing the printing of specific user-defined objects (e.g., GOOPS classes). In contrast, I want to globally override the REPL's printer to format all objects in a specific way, regardless of their type or origin.
I’m trying to customize the output format of the Guile REPL so that it displays additional information about the evaluated expressions. For example, when I evaluate 1
, I want the REPL to display:
1 (number)
Similarly, for a list like '(guix build gnu-build-system)
, I’d like the output to be formatted as:
#<list>
Item: guix (symbol)
Item: build (symbol)
Item: gnu-build-system (symbol)
I’ve written a function called repl-inspect
that formats objects in the desired way. Here’s a simplified version:
(use-modules (ice-9 pretty-print)) ; For pretty-printing
(use-modules (srfi srfi-1)) ; For list utilities
(use-modules (system repl repl)) ; For repl-print
;; ANSI color codes
(define *color-red* "\x1b[31m")
(define *color-green* "\x1b[32m")
(define *color-yellow* "\x1b[33m")
(define *color-blue* "\x1b[34m")
(define *color-magenta* "\x1b[35m")
(define *color-cyan* "\x1b[36m")
(define *color-reset* "\x1b[0m")
;; Custom type-of function
(define (type-of obj)
(cond
((struct? obj) 'struct)
((hash-table? obj) 'hash-table)
((variable? obj) 'variable)
((list? obj) 'list)
((pair? obj) 'pair)
((string? obj) 'string)
((symbol? obj) 'symbol)
((number? obj) 'number)
((boolean? obj) 'boolean)
((procedure? obj) 'procedure)
((char? obj) 'char)
((null? obj) 'null)
(else 'unknown)))
;; Helper to convert value to string and trim trailing whitespace
(define (value->string value)
(string-trim-right
(call-with-output-string
(lambda (port)
(pretty-print value port)))
#\newline))
;; Your inspect function
(define (repl-inspect obj depth)
(define (indent)
(display (make-string (* depth 2) #\space)))
(define (color-print color text)
(display color)
(display text)
(display *color-reset*))
(define (print-with-type value)
(display " (")
(color-print *color-yellow* (symbol->string (type-of value)))
(display ")"))
(cond
;; Handle structs
((struct? obj)
(indent)
(color-print *color-cyan* "#<struct>\n")
(let ((vtable (struct-vtable obj)))
(indent)
(color-print *color-yellow* "Vtable: ")
(display (value->string vtable))
(print-with-type vtable)
(newline)
(indent)
(color-print *color-yellow* "Fields:\n")
(catch #t
(lambda ()
(let loop ((index 0))
(catch #t
(lambda ()
(let ((field-value (struct-ref obj index)))
(indent)
(color-print *color-green* " Field ")
(display index)
(color-print *color-green* ": ")
(repl-inspect field-value (+ depth 1)) ; Recursively inspect each field
(loop (+ index 1))))
(lambda (key . args)
(indent)
(color-print *color-red* " (End of fields)\n")
(indent)
(color-print *color-red* " Error details: ")
(pretty-print (cons key args))))))
(lambda (key . args)
(indent)
(color-print *color-red* " (Cannot access struct fields)\n")
(indent)
(color-print *color-red* " Error details: ")
(pretty-print (cons key args))))))
;; Handle hash tables
((hash-table? obj)
(indent)
(color-print *color-magenta* "#<hash-table>\n")
(hash-for-each (lambda (key value)
(indent)
(color-print *color-green* " Key: ")
(display (value->string key))
(print-with-type key)
(newline)
(indent)
(color-print *color-green* " Value: ")
(repl-inspect value (+ depth 1))) ; Recursively inspect the value
obj))
;; Handle variables
((variable? obj)
(indent)
(color-print *color-blue* "#<variable>\n")
(indent)
(color-print *color-green* " Value: ")
(repl-inspect (variable-ref obj) (+ depth 1))) ; Inspect the value stored in the variable
;; Handle lists
((list? obj)
(indent)
(color-print *color-yellow* "#<list>\n")
(for-each (lambda (item)
(indent)
(color-print *color-green* " Item: ")
(repl-inspect item (+ depth 1))) ; Recursively inspect each item
obj))
;; Handle pairs (e.g., cons cells)
((pair? obj)
(indent)
(color-print *color-cyan* "#<pair>\n")
(indent)
(color-print *color-green* " Car: ")
(repl-inspect (car obj) (+ depth 1))
(indent)
(color-print *color-green* " Cdr: ")
(repl-inspect (cdr obj) (+ depth 1)))
;; Handle other types (base case)
(else
(indent)
(display (value->string obj))
(print-with-type obj)
(newline))))
;; Example usage
;(define interface (resolve-interface '(guix build gnu-build-system)))
;(repl-inspect interface 0)
How can I configure the Guile REPL to use my repl-inspect
function for displaying the results of evaluated expressions? Is there a way to override the default REPL printer or hook into the REPL’s output mechanism?
Upvotes: 0
Views: 45
Reputation: 2465
I found out!
Thanks to this old git repository. https://github.com/NalaGinrut/nala-repl/blob/master/nala/colorized.scm
Their purpose was adding a bit of color, to outputs of course nowadays you'd use guile-colorized
, but this gave me enough hints to find out
Assuming repl-inspect is already defined, you'd simply use
(use-modules (system repl common))
(define (repl-inspect-printer repl val)
(repl-inspect val 0))
(define (activate-repl-inspect-printer)
(let ((rs (fluid-ref *repl-stack*)))
(if (null? rs)
(repl-default-option-set! 'print repl-inspect-printer)
(repl-option-set! (car rs) 'print repl-inspect-printer))))
(activate-repl-inspect-printer)
In my case repl-inspect is what I wanted to use but you could use anything! I have to thank whoever Nala is!
Upvotes: 0