lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Proposal: support for custom grob and context properties


From: David Kastrup
Subject: Re: Proposal: support for custom grob and context properties
Date: Wed, 28 Sep 2016 03:24:47 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux)

Paul <address@hidden> writes:

> Hi all,
>
> It would be nice if LilyPond supported user-defined grob and context
> properties, for use in users' code -- in the spirit of practical
> software freedom and to further LilyPond's excellent extensibility. It
> would also be handy for prototyping code that might end up in
> LilyPond.
>
> Harm recently used custom properties in his BendSpanner-engraver, and
> I use them in my code for alternative notation systems.
>
> Currently this requires finding and copy/pasting the relevant scheme
> procedures so they can be used in your own files.  Namely,
> define-grob-property from scm/define-grob-properties.scm and
> translator-property-description from
> scm/define-context-properties.scm.
>
> Here are two possibilities for making this easier:
>
> 1. Make those two procedures "define-public" so users can just use
> them to define their own properties.  This requires very minimal
> change to LilyPond code, and is convenient for users since existing
> functions will just work for accessing and setting their custom
> properties (e.g. ly:grob-property).

The problem with the current implementation is that such additions are
not limited in scope and will persist beyond the currently processed
file.

> 2. Define a "custom-properties" grob property and a "customProperties"
> context property (or whatever name) that each holds an alist of user
> properties.  This adds additional properties to LilyPond and is a
> little more complex for the user to work with, but it provides
> isolation from LilyPond's properties.  (For example, users would only
> have to worry about conflicts with other user-defined properties, not
> conflicts with current or future LilyPond properties.)

This will not work with current code checks working with object
properties.

> I'm interested in implementing this one way or another.  Using the
> same approach for grob and context properties would make sense.
>
> Thoughts?

First you'd need to move is-grob? and its friends from the old "object
properties" interface to the new, function-calling one.  That's an
incompatible change.

Then you'd need to use a session-local defining function for defining
those properties, one that restores the startup state after each
session.

Here is some stone-age patch where you can see how the first step would
look in Scheme (the C++ part would no longer apply since
lily_module_constant has been superseded by the lily-imports.{cc,hh}
files).

All previous such "extensions" dabbling in internals would stop working.
So would previous checks for these properties (it's conceivable to
redefine the old object property accessor functions as they are not
likely to be used outside of LilyPond and a bit of performance impact
for legacy use would be tolerable).

>From b9ac44461c15db57cd8346053d8276e405487e53 Mon Sep 17 00:00:00 2001
From: David Kastrup <address@hidden>
Date: Wed, 15 Apr 2015 17:47:07 +0200
Subject: [PATCH] wip

---
 lily/include/lily-guile-macros.hh |  5 +++++
 lily/parser.yy                    |  6 ++----
 scm/define-grobs.scm              |  7 +++++--
 scm/document-translation.scm      |  2 +-
 scm/music-functions.scm           | 10 +++-------
 5 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/lily/include/lily-guile-macros.hh 
b/lily/include/lily-guile-macros.hh
index 5fc1c8e..984ebf1 100644
--- a/lily/include/lily-guile-macros.hh
+++ b/lily/include/lily-guile-macros.hh
@@ -215,6 +215,11 @@ void ly_check_name (const string &cxx, const string 
&fname);
 #define set_object(x, y) internal_set_object (ly_symbol2scm (x), y)
 #define del_property(x) internal_del_property (ly_symbol2scm (x))
 
+#define ly_set_object_property(name, object, value)                     \
+  (scm_call_2 (scm_setter (ly_lily_module_constant (name)), object, value))
+#define ly_get_object_property(name, object)    \
+  (scm_call_1 (ly_lily_module_constant (name), object))
+
 #ifndef NDEBUG
 /*
   TODO: include modification callback support here, perhaps
diff --git a/lily/parser.yy b/lily/parser.yy
index 2c324f5..a43ac31 100644
--- a/lily/parser.yy
+++ b/lily/parser.yy
@@ -2444,8 +2444,7 @@ grob_prop_spec:
                SCM l = scm_reverse_x ($1, SCM_EOL);
                if (scm_is_pair (l)
                    && to_boolean
-                   (scm_object_property (scm_car (l),
-                                         ly_symbol2scm ("is-grob?"))))
+                   (ly_get_object_property ("is-grob?", scm_car (l))))
                        l = scm_cons (ly_symbol2scm ("Bottom"), l);
                if (scm_is_null (l) || scm_is_null (scm_cdr (l))) {
                        parser->parser_error (@1, _ ("bad grob property path"));
@@ -2554,8 +2553,7 @@ simple_revert_context:
                $1 = scm_reverse_x ($1, SCM_EOL);
                if (scm_is_null ($1)
                    || to_boolean
-                   (scm_object_property (scm_car ($1),
-                                         ly_symbol2scm ("is-grob?")))) {
+                   (ly_get_object_property ("is-grob?", scm_car ($1)))) {
                        $$ = ly_symbol2scm ("Bottom");
                        parser->lexer_->push_extra_token (@1, SCM_IDENTIFIER, 
$1);
                } else {
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index 252733d..658fe67 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -2829,11 +2829,14 @@
 
 ;; make sure that \property Foo.Bar =\turnOff doesn't complain
 
+(define is-grob? (make-object-property))
+(define translation-type? (make-object-property))
+
 (for-each (lambda (x)
             ;; (display (car x)) (newline)
 
-            (set-object-property! (car x) 'translation-type? 
ly:grob-properties?)
-            (set-object-property! (car x) 'is-grob? #t))
+            (set! (translation-type? (car x)) ly:grob-properties?)
+            (set! (is-grob? (car x)) #t))
           all-grob-descriptions)
 
 (set! all-grob-descriptions (sort all-grob-descriptions alist<?))
diff --git a/scm/document-translation.scm b/scm/document-translation.scm
index 8de267f..43cd322 100644
--- a/scm/document-translation.scm
+++ b/scm/document-translation.scm
@@ -148,7 +148,7 @@
          (if (pretty-printable? value)
            (format #f ":~a\n" (scm->texi value))
            (format #f " ~a.\n" (scm->texi value))))))
-     ((equal? (object-property context-sym 'is-grob?) #t) "")
+     ((is-grob? context-sym) "")
      ((equal? tag 'assign)
       (string-append
         (format #f "@item Set translator property @code{~a} to" context-sym)
diff --git a/scm/music-functions.scm b/scm/music-functions.scm
index 611879a..b300f3e 100644
--- a/scm/music-functions.scm
+++ b/scm/music-functions.scm
@@ -433,17 +433,13 @@ respectively."
     ;; A Guile 1.x bug specific to optargs precludes moving the
     ;; defines out of the let
     (define (unspecial? s)
-      (not (or (object-property s 'is-grob?)
-               (object-property s 'backend-type?))))
-    (define (grob? s)
-      (object-property s 'is-grob?))
-    (define (property? s)
-      (object-property s 'backend-type?))
+      (not (or (is-grob? s)
+               (backend-type? s))))
     (define (check c p) (c p))
 
     (let* ((checkers
             (and (< start 3)
-                 (drop (list unspecial? grob? property?) start)))
+                 (drop (list unspecial? is-grob? backend-type?) start)))
            (res
             (cond
              ((null? path)
-- 
2.9.3


-- 
David Kastrup

reply via email to

[Prev in Thread] Current Thread [Next in Thread]