all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Jelle Licht <jlicht@posteo.net>
To: "Andrew Tropin" <andrew@trop.in>, "Ludovic Courtès" <ludo@gnu.org>
Cc: "\(" <paren@disroot.org>, David Wilson <david@daviwil.com>,
	60753@debbugs.gnu.org
Subject: [bug#60753] [PATCH] gnu: home: Add home-emacs-service-type.
Date: Wed, 01 Feb 2023 12:59:42 +0000	[thread overview]
Message-ID: <87lelhils1.fsf@posteo.net> (raw)
In-Reply-To: <87v8ktvq99.fsf@trop.in>

Andrew Tropin <andrew@trop.in> writes:

> On 2023-01-23 11:18, Ludovic Courtès wrote:
>
>> Hi,
>>
>> Andrew Tropin <andrew@trop.in> skribis:
>>
>>> On 2023-01-17 10:02, Ludovic Courtès wrote:
>>>
>>>> Hi,
>>>>
>>>> Andrew Tropin <andrew@trop.in> skribis:
>>>>
>>>>>> What about accepting sexps (or gexps) instead of strings?  As in:
>>>>>>
>>>>>>   (init-file '((require 'whatever) (setq something t)))
>>>>>
>>>>> A quick minor note on this approach: it won't be possible to use
>>>>> #'elisp-function inside such configuration because it will be
>>>>> interpreted by guile reader, but actually rde lives without this
>>>>> functionality completely ok.
>>>>
>>>> Specifically:
>>>>
>>>>   (write '#'x)
>>>>   |= (syntax x)
>>>>
>>>> But we can use (guix read-print) and ensure that it prints #'.
>>>>
>>>
>>> Do you have any links to docs/sample implementations on the topic of
>>> extending guile reader, so we have an example to start with?
>>
>> It’s not the reader but rather the writer that we’d want to tweak.
>
> Right, it already can read #'x as (syntax x) and we can print it
> properly later, but AFAIK comments are ignored by the default reader.
> So I would expect to do something (very roughly) like this:
>
> --8<---------------cut here---------------start------------->8---
> (parameterize (((@@ (guix gexp) read-procedure) read-with-comments))
>   #~(list 'hello ; Comment I would like to preserve during serialization
>           'guix))
> --8<---------------cut here---------------end--------------->8---
>
> Of course it doesn't work, but I hope demonstrates the idea.
>
>>
>> In (guix read-print), ‘pretty-print-with-comments’ already special
>> cases quasiquote etc. so that it prints ‘`’ (backtick) and not
>> ‘quasiquote'.  We’d add clauses for ‘syntax’ and ‘quasisyntax’.
>>
>
> It seems ice-9 pretty-print also preserves backticks, but I see that
> pretty-print-with-comments also preserves gexps, which is cool.  Adding
> syntax will make it even cooler.
>
>>> I think it will be cool to hook up a custom reader, ideally comment
>>> preserving, for emacs lisp inside scheme files.
>>
>> (guix read-print) is what you want.  :-)
>>
>
> Can you give a hint on how to use it for preserving comments, please?
>
>>>>> Do we want something like this possible?
>>>>>
>>>>> (init-file `((require 'whatever)
>>>>>              (setq something t)
>>>>>              (load ,(local-file "old-init.el")))
>>>>
>>>> It’d be nice.  In that case, we’ll want it to be a gexp though:
>>>>
>>>>   #~((require 'whatever) (load #$(local-file …)))
>>>>
>>>
>>> gexps are nice, but do we really need/want them here?  Do you have any
>>> thoughts on what are the benifits over quasiquotes in this case?  Maybe
>>> some examples?
>>
>> The benefit in the example above is that the gexp would actually work
>> whereas the sexp wouldn’t :-), unless there’s code somewhere to manually
>> traverse the sexp adn replace the <local-file> record with its store
>> item (which is what gexps are about).
>>
>> I hope that makes sense!
>
> With this simple serializer we already achieved quite good results: 
> https://git.sr.ht/~abcdw/rde/tree/388d3ad95e8607543df3dcdf26d058b610e77389/src/rde/serializers/lisp.scm#L35
>
> For this input
> --8<---------------cut here---------------start------------->8---
> `((load ,(local-file "./feature-lists.scm"))
>   ,#~(format #f "hello") ; top level gexps are evaluated
>   (list ,#~(format #f "hello")) ; nested gexps are not
>   ,#~";; hacky comment"
>   ;; comment, which is not preserved
>   #'hi-fn ; incorrectly serialized, but fixable by alternative
>           ; pretty-print
>   )
> --8<---------------cut here---------------end--------------->8---
>
> it provides quite satisfying results:
> --8<---------------cut here---------------start------------->8---
> (load "/gnu/store/xb6ma0mcgg1zzq645s63arvy3qskmbiz-feature-lists.scm")
> hello
> (list (format #f "hello"))
> ;; hacky comment
> (syntax hi-fn)
> --8<---------------cut here---------------end--------------->8---
>
> It's a little incosistent (top level gexp are evaluated, but nested are
> not), comments are not preserved and #' serialized incorrectly, but
> other than that it works very good.
>
> WDYT about overall approach used here?  or we can do it radically
> better?

Not saying it's better in any particular way, but I have had this locally
for all my elisp-read-by-guile-written-back-to-elisp needs:

--8<---------------cut here---------------start------------->8---
(define-module (jlicht build elisp-write)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-1)
  #:export (elisp-write))

(define (elisp-write in-list? exp port)
  "Stack-blowing implementation that writes guile's internal elisp
representation to something that can be parsed by Emacs."
  ;; Definitions from (language elisp parser)'s quotation-symbols: 
  (define symbol-strings
    '((#{`}# . "`")
      (#{,}# . ",")
      (#{,@}# . ",@")))
  (define (elisp-symbol? sym)
    (assq sym symbol-strings))
  (define (write-elisp-symbol sym port)
    (format port "~A" (assq-ref symbol-strings sym)))
  
  (match exp
    (((? elisp-symbol? sym) rest)
     (write-elisp-symbol sym port)
     (elisp-write in-list? rest port))
    ;; Vector expression
    (#(vs ...)
     (format port "[")
     (elisp-write #t vs port)
     (format port "]"))
    ;; Guile elisp implementation detail
    ('(%set-lexical-binding-mode #f) 'skip)
    ;; List walker
    ((e ...)
     (when (not in-list?) (format port "("))
     (unless (null? e)
       (elisp-write #f (car e) port)
       (for-each (lambda (v)
                   (format port " ")
                   (elisp-write #f v port)) (cdr e)))
     (when (not in-list?) (format port ")")))
    ;; dotted pair
    ((and (? pair?) (? dotted-list? l))
     (format port "(")
     (elisp-write #t (drop-right l 0) port)
     (format port " . ")
     (elisp-write #t (take-right l 0) port)
     (format port ")"))
    ;; Print simple primitives
    (_ (write exp port))))
--8<---------------cut here---------------end--------------->8---

On the reader side I just use guile's elisp reader:

--8<---------------cut here---------------start------------->8---
(define-module (jlicht test elisp)
  #:use-module (language elisp parser)
  #:use-module (jlicht build elisp-write)
  #:use-module (srfi srfi-26)
  #:use-module (srfi srfi-64))

(eval-when (expand load eval)
  (read-hash-extend #\e (lambda (chr port) (read-elisp port))))

(set! test-log-to-file #f)

(define (roundtrip expr)
  (let ((written (call-with-output-string (cut elisp-write #f expr <>))))
    (call-with-input-string written read-elisp)))

(define-syntax test-roundtrip-equals
  (syntax-rules ()
    ((_ expr)
     (let ((e1 (roundtrip expr)))
       (test-equal e1 (roundtrip e1))))))

(define runner (test-runner-simple))

(test-with-runner runner
  (test-begin "roundtrip-elisp-fixed-point")
  (test-roundtrip-equals 12)
  (test-roundtrip-equals "hello")
  (test-roundtrip-equals '#e#'my-fn)
  (test-roundtrip-equals '#e[a b c])
  (test-roundtrip-equals '#e`(+ 1 2 ,@(a b) ,c))
  (test-end "roundtrip-elisp-fixed-point"))

(exit (test-runner-fail-count runner))
--8<---------------cut here---------------end--------------->8---

I've also hooked it up in combination with a sequence of calls to
`scheme-file' -> `computed-file' called `elisp-file', but that's a bit
more hacky and less relevant to the current discussion.

- Jelle




  parent reply	other threads:[~2023-02-01 13:00 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-12 14:01 [bug#60753] [PATCH] gnu: home: Add home-emacs-service-type David Wilson
2023-01-12 17:24 ` ( via Guix-patches via
2023-01-12 17:27   ` David Wilson
2023-01-14 18:00     ` Ludovic Courtès
2023-01-15  8:02       ` Andrew Tropin
2023-01-17  9:02         ` Ludovic Courtès
2023-01-17 14:46           ` Andrew Tropin
2023-01-23 10:18             ` Ludovic Courtès
2023-01-26  5:06               ` Andrew Tropin
2023-01-31 16:26                 ` Ludovic Courtès
2023-02-01 14:06                   ` Andrew Tropin
2023-02-10  7:50                   ` David Wilson
2023-02-20 11:10                     ` Ludovic Courtès
2023-02-01 12:59                 ` Jelle Licht [this message]
2023-02-01 13:46                   ` Andrew Tropin
2023-01-26 18:50           ` Reily Siegel
2023-01-16  9:25       ` David Wilson
2023-01-15  0:21 ` [bug#60753] file like parameters not working benoit
2023-01-15  2:07 ` [bug#60753] issue with file-like init file benoit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lelhils1.fsf@posteo.net \
    --to=jlicht@posteo.net \
    --cc=60753@debbugs.gnu.org \
    --cc=andrew@trop.in \
    --cc=david@daviwil.com \
    --cc=ludo@gnu.org \
    --cc=paren@disroot.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.