]> git.donarmstrong.com Git - lilypond.git/commitdiff
New alist to replace special characters.
authorBertrand Bordage <bordage.bertrand@gmail.com>
Fri, 29 Jul 2011 21:26:45 +0000 (23:26 +0200)
committerBertrand Bordage <bordage.bertrand@gmail.com>
Sat, 24 Sep 2011 10:39:24 +0000 (12:39 +0200)
* A list of ASCII aliases for special characters has been added.
* New add-text-replacements! command for \paper blocks.
* New markup command \replace.

14 files changed:
Documentation/changes.tely
Documentation/included/special-characters.ly [new file with mode: 0644]
Documentation/notation/input.itely
Documentation/notation/notation-appendices.itely
Documentation/notation/vocal.itely
input/regression/markup-special-characters.ly [new file with mode: 0644]
lily/lexer.ll
lily/text-interface.cc
ly/paper-defaults-init.ly
ly/text-replacements.ly [new file with mode: 0644]
scm/define-grob-properties.scm
scm/define-markup-commands.scm
scm/lily.scm
scm/text.scm [new file with mode: 0644]

index c4e3332f132addb0033e685c5cfc57a6f83678ad..f7d6faf885206c703a1bb3dc7d5c2a7fb055283b 100644 (file)
@@ -75,6 +75,15 @@ dyn=#(define-event-function (parser location arg) (markup?)
 \relative c' { c\dyn pfsss }
 @end lilypond
 
+@item
+A list of ASCII aliases for special characters can be included.
+@lilypond[quote,verbatim]
+\paper {
+  #(include-special-characters)
+}
+\markup "&bull; &dagger; &copyright; &OE; &ss; &para;"
+@end lilypond
+
 @item
 There is a new @code{define-scheme-function} command in analogy to
 @code{define-music-function} that can be used to define functions
diff --git a/Documentation/included/special-characters.ly b/Documentation/included/special-characters.ly
new file mode 100644 (file)
index 0000000..7c6f272
--- /dev/null
@@ -0,0 +1,18 @@
+\version "2.15.13"
+
+#(set-default-paper-size "a4")
+\paper {
+  #(include-special-characters)
+}
+
+#(define-markup-list-command (show-special-characters layout props) ()
+   (let ((defs (ly:output-def-lookup layout 'text-font-defaults)))
+        (interpret-markup-list layout props
+          (map (lambda (pair)
+            (markup #:override '(line-width . 18)
+                    #:fill-line
+                    (#:override '(replacement-alist . ()) (car pair)
+                     #:override '(thickness . 0.1) #:box (cdr pair))))
+            (list-tail (assoc-get 'replacement-alist defs) 3)))))
+
+\markuplines \justified-lines \show-special-characters
index 3f05fda34362ef422c306af7d5bc84ca1d39dbf5..e418d96fb4076221e79b344cd1962f2800fce41c 100644 (file)
@@ -1200,7 +1200,7 @@ Init files: @file{../ly/toc-init.ly}.
 @menu
 * Including LilyPond files::
 * Different editions from one source::
-* Text encoding::
+* Special characters::
 @end menu
 
 
@@ -1605,12 +1605,23 @@ Learning Manual:
 Notation Reference:
 @ref{Including LilyPond files}.
 
+@node Special characters
+@subsection Special characters
+
+@cindex special characters
+@cindex non-ASCII characters
+
+@menu
+* Text encoding::
+* Unicode::
+* ASCII aliases::
+@end menu
+
+
 @node Text encoding
-@subsection Text encoding
+@unnumberedsubsubsec Text encoding
 
-@cindex Unicode
 @cindex UTF-8
-@cindex non-ASCII characters
 
 LilyPond uses the character repertoire defined by the Unicode
 consortium and ISO/IEC 10646.  This defines a unique name and
@@ -1675,6 +1686,12 @@ portuguese = \lyricmode {
 \addlyrics { \portuguese }
 @end lilypond
 
+
+@node Unicode
+@unnumberedsubsubsec Unicode
+
+@cindex Unicode
+
 To enter a single character for which the Unicode code point is
 known but which is not available in the editor being used, use
 either @code{\char ##xhhhh} or @code{\char #dddd} within a
@@ -1724,6 +1741,58 @@ To enter the copyright sign in the copyright notice use:
 @end example
 
 
+@node ASCII aliases
+@unnumberedsubsubsec ASCII aliases
+
+A list of ASCII aliases for special characters can be included:
+
+@lilypond[quote,verbatim]
+\paper {
+  #(include-special-characters)
+}
+
+\markup "&flqq; &ndash; &OE;uvre incomplète&hellip; &frqq;"
+
+\score {
+  \new Staff { \repeat unfold 9 a'4 }
+  \addlyrics {
+    This is al -- so wor -- kin'~in ly -- rics: &ndash;_&OE;&hellip;
+  }
+}
+
+\markup \column {
+  "The replacement can be disabled:"
+  "&ndash; &OE; &hellip;"
+  \override #'(replacement-alist . ()) "&ndash; &OE; &hellip;"
+}
+@end lilypond
+
+You can also make your own aliases, either globally:
+
+@lilypond[quote,verbatim]
+\paper {
+  #(add-text-replacements!
+    '(("100" . "hundred")
+      ("dpi" . "dots per inch")))
+}
+\markup "A 100 dpi."
+@end lilypond
+
+or locally:
+
+@lilypond[quote,verbatim]
+\markup \replace #'(("100" . "hundred")
+                    ("dpi" . "dots per inch")) "A 100 dpi."
+@end lilypond
+
+@seealso
+Notation Reference:
+@ref{List of special characters}.
+
+Installed Files:
+@file{ly/text-replacements.ly}.
+
+
 
 @node Controlling output
 @section Controlling output
index 53c75c035164c5ff42e65954a38f8d7c6c004365..81b43d93907701d9ef2886fe5ba55637f603d5c3 100644 (file)
@@ -24,6 +24,7 @@
 * Note head styles::
 * Text markup commands::
 * Text markup list commands::
+* List of special characters::
 * List of articulations::
 * Percussion notes::
 * Technical glossary::
@@ -901,6 +902,24 @@ The following commands can all be used with @code{\markuplines}:
 @include markup-list-commands.tely
 
 
+@node List of special characters
+@appendixsec List of special characters
+
+The following special characters references can be used;
+for more details, see @ref{ASCII aliases}.
+
+The HTML syntax is used and most of these references are the same as HTML.
+The rest of them are inspired by @LaTeX{}.
+
+The characters are boxed so that you can see their size.
+A small padding has been added between the character and the box
+for more readability.
+
+@lilypond[quote]
+\include "special-characters.ly"
+@end lilypond
+
+
 @node List of articulations
 @appendixsec List of articulations
 
@@ -1125,7 +1144,7 @@ a set of fonts covering several styles and sizes comprise a typeface.
 @seealso
 Notation Reference:
 @ref{Fonts},
-@ref{Text encoding}.
+@ref{Special characters}.
 
 
 @node grob
index 70f7c929868bfc80aa99682372e402de31167879..0890ed6455068b2d35d8f549cc24ea57247b01cc 100644 (file)
@@ -171,7 +171,7 @@ Punctuation, lyrics with accented characters, characters from
 non-English languages, or special characters (such as the heart
 symbol or slanted quotes), may simply be inserted directly
 into the input file, providing it is saved with UTF-8 encoding.
-For more information, see @ref{Text encoding}.
+For more information, see @ref{Special characters}.
 
 @lilypond[quote,verbatim]
 \relative c'' { d8 c16 a bes8 f e' d c4 }
@@ -218,7 +218,7 @@ Notation Reference:
 @ref{Formatting text},
 @ref{Input modes},
 @ref{Manual syllable durations},
-@ref{Text encoding}.
+@ref{Special characters}.
 
 Internals Reference:
 @rinternals{LyricText}.
diff --git a/input/regression/markup-special-characters.ly b/input/regression/markup-special-characters.ly
new file mode 100644 (file)
index 0000000..6e8b6e0
--- /dev/null
@@ -0,0 +1,30 @@
+\version "2.15.13"
+\header {
+  texidoc = "
+  A list of special character ASCII aliases can be easily included.
+  This works for markups and lyrics.
+"
+}
+
+\paper {
+  #(include-special-characters)
+  indent = 0
+}
+
+\markup \column {
+  \bold "Markup example:"
+  "Input:"
+  \override #'(replacement-alist . ()) \typewriter \justify {
+    &numero;2 &ndash; &OE;dipe&hellip;
+  }
+  "Output:"
+  \italic \justify {
+    &numero;2 &ndash; &OE;dipe&hellip;
+  }
+  \vspace #0.5
+  \bold "Lyric example:"
+}
+\new Lyrics \lyricmode {
+  Ce&s;16 -- &s;ez In -- fi -- dè -- les, un c&oe;ur in -- no -- cent
+  ne craint rien&nnbsp;;
+}
index 3445b6b7847c5add6332478ba68519a977ef6b78..2b79c4dab711aaf99443e5feef3aa282709a9d46 100644 (file)
@@ -133,8 +133,9 @@ AN          {AA}|{N}
 ANY_CHAR       (.|\n)
 PUNCT          [?!:'`]
 ACCENT         \\[`'"^]
+SPECIAL_CHAR           [&@]
 NATIONAL       [\001-\006\021-\027\031\036]
-TEX            {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}
+TEX            {AA}|-|{PUNCT}|{ACCENT}|{NATIONAL}|{SPECIAL_CHAR}
 DASHED_WORD            {A}({AN}|-)*
 DASHED_KEY_WORD                \\{DASHED_WORD}
 
index 232d9c3824a80bd36420c7c84dd9c07efd654ed8..47171b0949c2fbc5ccd9ac35f92c426edb8e6af0 100644 (file)
 #include "warn.hh"
 
 static void
-replace_whitespace (string *str)
+replace_special_characters (string *str, SCM props)
 {
   vsize i = 0;
-  vsize n = str->size ();
+  SCM replacement_alist = ly_chain_assoc_get (ly_symbol2scm ("replacement-alist"),
+                                              props,
+                                              SCM_EOL);
 
-  while (i < n)
+  int max_length = 0;
+  for (SCM s = replacement_alist; scm_is_pair (s); s = scm_cdr (s))
     {
-      char cur = (*str)[i];
-
-      // avoid the locale-dependent isspace
-      if (cur == '\n' || cur == '\t' || cur == '\v')
-        (*str)[i] = ' ';
-
-      vsize char_len = utf8_char_len (cur);
+      max_length = max (max_length, scm_to_int
+                        (scm_string_length (scm_caar (s))));
+    }
 
-      i += char_len;
+  while (i <= str->size ())
+    {
+      for (vsize j = max_length + 1; j--;)
+        {
+          string dummy = str->substr (i, j);
+          string ligature = robust_scm2string
+                            (ly_assoc_get (ly_string2scm (dummy),
+                                           replacement_alist, SCM_BOOL_F), "");
+          if (ligature != "")
+            str->replace (i, j, ligature);
+        }
+      i += utf8_char_len ((*str)[i]);
     }
 }
 
@@ -65,7 +75,7 @@ Text_interface::interpret_string (SCM layout_smob,
   Output_def *layout = unsmob_output_def (layout_smob);
   Font_metric *fm = select_encoded_font (layout, props);
 
-  replace_whitespace (&str);
+  replace_special_characters (&str, props);
 
   /*
     We want to filter strings with a music font that pass through
@@ -114,22 +124,22 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup)
             {
               string name = ly_symbol2string (scm_procedure_name (func));
               // TODO: Also print the arguments of the markup!
-              non_fatal_error (_f("Cyclic markup detected: %s", name));
-              return Stencil().smobbed_copy ();
+              non_fatal_error (_f ("Cyclic markup detected: %s", name));
+              return Stencil ().smobbed_copy ();
             }
         }
 
       /* Check for non-terminating markups, e.g. recursive calls with
        * changing arguments */
       SCM opt_depth = ly_get_option (ly_symbol2scm ("max-markup-depth"));
-      size_t max_depth = robust_scm2int(opt_depth, 1024);
+      size_t max_depth = robust_scm2int (opt_depth, 1024);
       if (depth > max_depth)
         {
           string name = ly_symbol2string (scm_procedure_name (func));
           // TODO: Also print the arguments of the markup!
-          non_fatal_error (_f("Markup depth exceeds maximal value of %d; "
-                              "Markup: %s", max_depth, name.c_str ()));
-          return Stencil().smobbed_copy ();
+          non_fatal_error (_f ("Markup depth exceeds maximal value of %d; "
+                               "Markup: %s", max_depth, name.c_str ()));
+          return Stencil ().smobbed_copy ();
         }
 
       encountered_markups.push_back (markup);
@@ -188,6 +198,7 @@ ADD_INTERFACE (Text_interface,
 
                /* properties */
                "baseline-skip "
+               "replacement-alist "
                "text "
                "word-space "
                "text-direction "
index d08c665f570767712e02f2dad6a836d0a8e82fea..5fa0080778339c11f31909b7e7ce4719209e9740 100644 (file)
   #(define text-font-defaults
      `((font-encoding . latin1)
        (baseline-skip . 3)
+       (replacement-alist . ,default-string-replacement-alist)
        (word-space . 0.6)))
 
+  \include "text-replacements.ly"
+
 }
diff --git a/ly/text-replacements.ly b/ly/text-replacements.ly
new file mode 100644 (file)
index 0000000..94d3dac
--- /dev/null
@@ -0,0 +1,133 @@
+%%%% This file is part of LilyPond, the GNU music typesetter.
+%%%%
+%%%% Copyright (C) 2011 Bertrand Bordage <bordage.bertrand@gmail.com>
+%%%%
+%%%% LilyPond is free software: you can redistribute it and/or modify
+%%%% it under the terms of the GNU General Public License as published by
+%%%% the Free Software Foundation, either version 3 of the License, or
+%%%% (at your option) any later version.
+%%%%
+%%%% LilyPond is distributed in the hope that it will be useful,
+%%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%%%% GNU General Public License for more details.
+%%%%
+%%%% You should have received a copy of the GNU General Public License
+%%%% along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+
+\version "2.15.13"
+
+#(define (add-text-replacements! alist)
+   (assoc-set! text-font-defaults 'replacement-alist
+     (cdaar
+       (internal-add-text-replacements (list text-font-defaults) alist))))
+
+#(define (include-special-characters)
+   (add-text-replacements!
+     '(;; Punctuation
+       ("&hellip;" . "…")
+       ("&ndash;" . "–")
+       ("&mdash;" . "—")
+       ("&iexcl;" . "¡")
+       ("&iquest;" . "¿")
+       ("&solidus;" . "∕") ; this is not a slash,
+                           ; contrary to what is said in Unicode.
+
+       ;; French, German and English quotes open/close
+       ("&flq;" . "‹")
+       ("&frq;" . "›")
+       ("&flqq;" . "«")
+       ("&frqq;" . "»")
+       ("&glq;" . "‚")
+       ("&grq;" . "‘")
+       ("&glqq;" . "„")
+       ("&grqq;" . "“")
+       ("&elq;" . "‘")
+       ("&erq;" . "’")
+       ("&elqq;" . "“")
+       ("&erqq;" . "”")
+
+       ;; Word dividers
+       ("&ensp;" . " ")
+       ("&emsp;" . " ")
+       ("&thinsp;" . " ")
+       ("&nbsp;" . " ")
+       ("&nnbsp;" . " ") ; narrow non-breaking space
+       ("&zwj;" . "‍")
+       ("&zwnj;" . "‌")
+       ("&middot;" . "·") ; interpunct
+
+       ;; General typography
+       ("&bull;" . "•")
+       ("&copyright;" . "©")
+       ("&registered;" . "®")
+       ("&trademark;" . "™")
+       ("&dagger;" . "†")
+       ("&Dagger;" . "‡")
+       ("&numero;" . "№")
+       ("&ordf;" . "ª")
+       ("&ordm;" . "º")
+       ("&para;" . "¶")
+       ("&sect;" . "§")
+       ("&deg;" . "°")
+       ("&numero;" . "№")
+       ("&permil;" . "‰")
+       ("&brvbar;" . "¦")
+
+       ;; Diacritics
+       ("&acute;" . "´")
+       ("&acutedbl;" . "˝")
+       ("&grave;" . "`")
+       ("&breve;" . "˘")
+       ("&caron;" . "ˇ")
+       ("&cedilla;" . "¸")
+       ("&circumflex;" . "^")
+       ("&diaeresis;" . "¨")
+       ("&macron;" . "¯")
+
+       ;; Non-ASCII Letters (Excluding Accented Letters)
+       ("&aa;" . "å")
+       ("&AA;" . "Å")
+       ("&ae;" . "æ")
+       ("&AE;" . "Æ")
+       ("&dh;" . "ð")
+       ("&DH;" . "Ð")
+       ("&dj;" . "đ")
+       ("&DJ;" . "Đ")
+       ("&l;" . "ł")
+       ("&L;" . "Ł")
+       ("&ng;" . "ŋ")
+       ("&NG;" . "Ŋ")
+       ("&o;" . "ø")
+       ("&O;" . "Ø")
+       ("&oe;" . "œ")
+       ("&OE;" . "Œ")
+       ("&s;" . "ſ")
+       ("&ss;" . "ß")
+       ("&th;" . "þ")
+       ("&TH;" . "Þ")
+
+       ;; Mathematical symbols
+       ("&plus;" . "+")
+       ("&minus;" . "−")
+       ("&times;" . "×")
+       ("&div;" . "÷")
+       ("&sup1;" . "¹")
+       ("&sup2;" . "²")
+       ("&sup3;" . "³")
+       ("&sqrt;" . "√")
+       ("&increment;" . "∆")
+       ("&infty;" . "∞")
+       ("&sum;" . "∑")
+       ("&pm;" . "±")
+       ("&bulletop;" . "∙")
+       ("&partial;" . "∂")
+       ("&neg;" . "¬")
+
+       ;; Currency symbols
+       ("&currency;" . "¤")
+       ("&dollar;" . "$")
+       ("&euro;" . "€")
+       ("&pounds;" . "£")
+       ("&yen;" . "¥")
+       ("&cent;" . "¢"))))
index ecd67e5b122df92430f7465fc9f61bc1b3e1b67d..ec0ff1e37f7e05d15c9a998b7ba10aad58563c17 100644 (file)
@@ -681,6 +681,9 @@ number, the quicker the slur attains its @code{height-limit}.")
 interesting items.")
      (remove-first ,boolean? "Remove the first staff of an orchestral
 score?")
+     (replacement-alist ,list? "Alist of strings.
+The key is a string of the pattern to be replaced.  The value is a
+string of what should be displayed.  Useful for ligatures.")
      (restore-first ,boolean? "Print a natural before the
 accidental.")
      (rhythmic-location ,rhythmic-location? "Where (bar number,
index 6ac78bac77a4df046666d7028f0d8cd9e28d8fa6..4b2aff53249716d38d60cdd6c6a419d64994b04f 100644 (file)
@@ -2153,16 +2153,18 @@ Adjusts @code{baseline-skip} and @code{word-space} accordingly.
 }
 @end lilypond"
   (let* ((ref-size (ly:output-def-lookup layout 'text-font-size 12))
-        (text-props (list (ly:output-def-lookup layout 'text-font-defaults)))
-        (ref-word-space (chain-assoc-get 'word-space text-props 0.6))
-        (ref-baseline (chain-assoc-get 'baseline-skip text-props 3))
-        (magnification (/ size ref-size)))
-    (interpret-markup layout
-                     (cons `((baseline-skip . ,(* magnification ref-baseline))
-                             (word-space . ,(* magnification ref-word-space))
-                             (font-size . ,(magnification->font-size magnification)))
-                           props)
-                     arg)))
+         (text-props (list (ly:output-def-lookup layout 'text-font-defaults)))
+         (ref-word-space (chain-assoc-get 'word-space text-props 0.6))
+         (ref-baseline (chain-assoc-get 'baseline-skip text-props 3))
+         (magnification (/ size ref-size)))
+     (interpret-markup
+      layout
+      (cons
+       `((baseline-skip . ,(* magnification ref-baseline))
+         (word-space . ,(* magnification ref-word-space))
+         (font-size . ,(magnification->font-size magnification)))
+       props)
+      arg)))
 
 (define-markup-command (fontsize layout props increment arg)
   (number? markup?)
@@ -2181,11 +2183,14 @@ accordingly.
   smaller
 }
 @end lilypond"
-  (let ((entries (list
-                  (cons 'baseline-skip (* baseline-skip (magstep increment)))
-                  (cons 'word-space (* word-space (magstep increment)))
-                  (cons 'font-size (+ font-size increment)))))
-    (interpret-markup layout (cons entries props) arg)))
+  (interpret-markup
+   layout
+   (cons
+    `((baseline-skip . ,(* baseline-skip (magstep increment)))
+      (word-space . ,(* word-space (magstep increment)))
+      (font-size . ,(+ font-size increment)))
+    props)
+   arg))
 
 (define-markup-command (magnify layout props sz arg)
   (number? markup?)
@@ -3690,6 +3695,28 @@ Patterns are aligned to the @var{dir} markup.
                               #:pattern (1+ count) X space pattern
                               right))))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Replacements
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define-markup-command (replace layout props replacements arg)
+  (list? markup?)
+  #:category font
+  "
+Used to automatically replace a string by another in the markup @var{arg}.
+Each pair of the alist @var{replacements} specifies what should be replaced.
+The @code{key} is the string to be replaced by the @code{value} string.
+
+@lilypond[verbatim, quote]
+\\markup \\replace #'((\"thx\" . \"Thanks!\")) thx
+@end lilypond"
+  (interpret-markup
+   layout
+   (internal-add-text-replacements
+    props
+    replacements)
+   (markup arg)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Markup list commands
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
index 193bf5df77f259f7942b07b1c7f924f71eda0aac..feec950c45e782717dcfae1b1d2fd1c84ede3111 100644 (file)
@@ -452,6 +452,7 @@ LilyPond safe mode.  The syntax is the same as `define*-public'."
     "define-grob-interfaces.scm"
     "define-stencil-commands.scm"
     "titling.scm"
+    "text.scm"
 
     "paper.scm"
     "backend-library.scm"
diff --git a/scm/text.scm b/scm/text.scm
new file mode 100644 (file)
index 0000000..3322c0e
--- /dev/null
@@ -0,0 +1,29 @@
+;;;; This file is part of LilyPond, the GNU music typesetter.
+;;;;
+;;;; Copyright (C) 2011 Bertrand Bordage <bordage.bertrand@gmail.com>
+;;;;
+;;;; LilyPond is free software: you can redistribute it and/or modify
+;;;; it under the terms of the GNU General Public License as published by
+;;;; the Free Software Foundation, either version 3 of the License, or
+;;;; (at your option) any later version.
+;;;;
+;;;; LilyPond is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+
+
+(define-public default-string-replacement-alist
+  '(;; Whitespaces
+    ("\t" . " ")
+    ("\n" . " ")
+    ("\v" . " ")))
+
+(define-public (internal-add-text-replacements props alist)
+  (let* ((dummy-replacements (chain-assoc-get 'replacement-alist props '()))
+         (new-replacements
+           (append dummy-replacements alist)))
+    (prepend-alist-chain 'replacement-alist new-replacements props)))