> How did you do that? Sorry to rain on your parade, but I would not > want you to put a lot of work in it if it will not be of mergeable > quality.
Attached. In the end the necessary modifications were surprisingly minor. Please comment, there is certainly room for improvements. Werner
diff --git a/lily/lyric-hyphen.cc b/lily/lyric-hyphen.cc index 23cd76bd94..897de7d7f7 100644 --- a/lily/lyric-hyphen.cc +++ b/lily/lyric-hyphen.cc @@ -48,6 +48,10 @@ Lyric_hyphen::print (SCM smob) && !from_scm<bool> (get_property (me, "after-line-breaking")))) return SCM_EOL; + // Ensure that bounds are displaced first. + (void) get_property (bounds[LEFT], "after-line-breaking"); + (void) get_property (bounds[RIGHT], "after-line-breaking"); + Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS); Interval span_points; diff --git a/scm/scheme-engravers.scm b/scm/scheme-engravers.scm index 07e3be3691..5131beef1f 100644 --- a/scm/scheme-engravers.scm +++ b/scm/scheme-engravers.scm @@ -943,6 +943,101 @@ Engraver to print a line between two @code{Fingering} grobs."))) (description . "Create repeat counts within lyrics for modern transcriptions of Gregorian chant."))) +(define (Left_hyphen_pointer_engraver context) + (let ((hyphen #f) + (text #f)) + (make-engraver + (acknowledgers + ((lyric-syllable-interface engraver grob source-engraver) + (set! text grob))) + (end-acknowledgers + ((lyric-hyphen-interface engraver grob source-engraver) + (when (not (grob::has-interface grob 'lyric-space-interface)) + (set! hyphen grob)))) + ((stop-translation-timestep engraver) + (when (and text hyphen) + (ly:grob-set-object! text 'left-hyphen hyphen)) + (set! text #f) + (set! hyphen #f))))) + +(define-public (lyric-text::apply-magnetic-offset! grob) + "If the space between two syllables is less than the value in +property @code{LyricText@/.details@/.squash-threshold}, move the right +syllable to the left so that it gets concatenated with the left +syllable. + +Use this function as a hook for +@code{LyricText@/.after-@/line-@/breaking} if the +@code{Left_@/hyphen_@/pointer_@/engraver} is active." + (let ((hyphen (ly:grob-object grob 'left-hyphen #f))) + (when hyphen + (let ((left-text (ly:spanner-bound hyphen LEFT))) + (when (grob::has-interface left-text 'lyric-syllable-interface) + (let* ((common (ly:grob-common-refpoint grob left-text X)) + (this-x-ext (ly:grob-extent grob common X)) + (left-x-ext + (begin + ;; Trigger magnetism for left-text. + (ly:grob-property left-text 'after-line-breaking) + (ly:grob-extent left-text common X))) + ;; `delta` is the gap width between two syllables. + (delta (- (interval-start this-x-ext) + (interval-end left-x-ext))) + (details (ly:grob-property grob 'details)) + (threshold (assoc-get 'squash-threshold details 0.2))) + (when (< delta threshold) + (let* (;; We have to manipulate the input text so that + ;; ligatures crossing syllable boundaries are not + ;; disabled. For languages based on the Latin + ;; script this is essentially a beautification. + ;; However, for non-Western scripts it can be a + ;; necessity. + (lt (ly:grob-property left-text 'text)) + (rt (ly:grob-property grob 'text)) + ;; Append new syllable. + (ltrt (if (and (string? lt) (string? rt)) + (string-append lt rt) + (make-concat-markup (list lt rt)))) + ;; Right-align `ltrt` to the right side. + (markup (grob-interpret-markup + grob + (make-translate-markup + (cons (interval-length this-x-ext) 0) + (make-right-align-markup ltrt))))) + (begin + ;; Don't print `left-text`. + (ly:grob-set-property! left-text 'stencil #f) + ;; Set text and stencil (which holds all collected + ;; syllables so far) and shift it to the left. + (ly:grob-set-property! grob 'text ltrt) + (ly:grob-set-property! grob 'stencil markup) + (ly:grob-translate-axis! grob (- delta) X)))))))))) + +(ly:register-translator + Left_hyphen_pointer_engraver 'Left_hyphen_pointer_engraver + '((grobs-created . ()) + (events-accepted . ()) + (properties-read . ()) + (properties-written . ()) + (description . "\ +Collect syllable-hyphen-syllable occurrences in lyrics and store them +in properties. This engraver only looks to the left. For example, if +the lyrics input is @code{foo -- bar}, it does the following. + +@itemize @bullet +@item +Set the @code{text} property of the @code{LyricHyphen} grob between +@q{foo} and @q{bar} to @code{foo}. + +@item +Set the @code{left-hyphen} property of the @code{LyricText} grob with +text @q{foo} to the @code{LyricHyphen} grob between @q{foo} and +@q{bar}. +@end itemize + +Use this auxiliary engraver in combination with the +@code{lyric-@/text::@/apply-@/magnetic-@/offset!} hook."))) + ; TODO: yet another engraver for alignment... Ultimately, it would be nice to ; merge Dynamic_align_engraver, Piano_pedal_align_engraver and ; Centered_bar_number_align_engraver.
\version "2.23.8" << \new Voice = "foo" \relative c'' { \omit Staff.TimeSignature \time 6/4 d4 d d d d d | } \new Lyrics \lyricsto "foo" { ibif -- icif -- if -- if -- ilif -- imif } >> \paper { indent = 0 ragged-right = ##f line-width = 50\mm } \layout { \context { \Lyrics \consists Left_hyphen_pointer_engraver \override LyricText.after-line-breaking = #lyric-text::apply-magnetic-offset! \override LyricText.details.squash-threshold = 0.5 \override LyricHyphen.minimum-length = 0.5 \override LyricHyphen.minimum-distance = 0 \override LyricSpace.minimum-distance = 1 } }
magnetic-lyrics-test.pdf
Description: Adobe PDF document