From: Bertrand Bordage Date: Fri, 29 Jul 2011 21:26:45 +0000 (+0200) Subject: New alist to replace special characters. X-Git-Tag: release/2.15.13-1~12 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=688f5f1711d8ca07338385a2ae0191b1a8aae315;p=lilypond.git New alist to replace special characters. * A list of ASCII aliases for special characters has been added. * New add-text-replacements! command for \paper blocks. * New markup command \replace. --- diff --git a/Documentation/changes.tely b/Documentation/changes.tely index c4e3332f13..f7d6faf885 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -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 "• † ©right; &OE; &ss; ¶" +@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 index 0000000000..7c6f2728bf --- /dev/null +++ b/Documentation/included/special-characters.ly @@ -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 diff --git a/Documentation/notation/input.itely b/Documentation/notation/input.itely index 3f05fda343..e418d96fb4 100644 --- a/Documentation/notation/input.itely +++ b/Documentation/notation/input.itely @@ -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; – &OE;uvre incomplète… &frqq;" + +\score { + \new Staff { \repeat unfold 9 a'4 } + \addlyrics { + This is al -- so wor -- kin'~in ly -- rics: –_&OE;… + } +} + +\markup \column { + "The replacement can be disabled:" + "– &OE; …" + \override #'(replacement-alist . ()) "– &OE; …" +} +@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 diff --git a/Documentation/notation/notation-appendices.itely b/Documentation/notation/notation-appendices.itely index 53c75c0351..81b43d9390 100644 --- a/Documentation/notation/notation-appendices.itely +++ b/Documentation/notation/notation-appendices.itely @@ -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 diff --git a/Documentation/notation/vocal.itely b/Documentation/notation/vocal.itely index 70f7c92986..0890ed6455 100644 --- a/Documentation/notation/vocal.itely +++ b/Documentation/notation/vocal.itely @@ -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 index 0000000000..6e8b6e0de3 --- /dev/null +++ b/input/regression/markup-special-characters.ly @@ -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 { + №2 – &OE;dipe… + } + "Output:" + \italic \justify { + №2 – &OE;dipe… + } + \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;; +} diff --git a/lily/lexer.ll b/lily/lexer.ll index 3445b6b784..2b79c4dab7 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -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} diff --git a/lily/text-interface.cc b/lily/text-interface.cc index 232d9c3824..47171b0949 100644 --- a/lily/text-interface.cc +++ b/lily/text-interface.cc @@ -33,22 +33,32 @@ #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 " diff --git a/ly/paper-defaults-init.ly b/ly/paper-defaults-init.ly index d08c665f57..5fa0080778 100644 --- a/ly/paper-defaults-init.ly +++ b/ly/paper-defaults-init.ly @@ -148,6 +148,9 @@ #(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 index 0000000000..94d3dacc2e --- /dev/null +++ b/ly/text-replacements.ly @@ -0,0 +1,133 @@ +%%%% This file is part of LilyPond, the GNU music typesetter. +%%%% +%%%% Copyright (C) 2011 Bertrand Bordage +%%%% +%%%% 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 . + +\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 + ("…" . "…") + ("–" . "–") + ("—" . "—") + ("¡" . "¡") + ("¿" . "¿") + ("&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 + (" " . " ") + (" " . " ") + (" " . " ") + (" " . " ") + ("&nnbsp;" . " ") ; narrow non-breaking space + ("‍" . "‍") + ("‌" . "‌") + ("·" . "·") ; interpunct + + ;; General typography + ("•" . "•") + ("©right;" . "©") + ("®istered;" . "®") + ("&trademark;" . "™") + ("†" . "†") + ("‡" . "‡") + ("№" . "№") + ("ª" . "ª") + ("º" . "º") + ("¶" . "¶") + ("§" . "§") + ("°" . "°") + ("№" . "№") + ("‰" . "‰") + ("¦" . "¦") + + ;; Diacritics + ("´" . "´") + ("´dbl;" . "˝") + ("`" . "`") + ("˘" . "˘") + ("ˇ" . "ˇ") + ("¸la;" . "¸") + ("&circumflex;" . "^") + ("&diaeresis;" . "¨") + ("¯on;" . "¯") + + ;; 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 + ("+" . "+") + ("−" . "−") + ("×" . "×") + ("÷" . "÷") + ("¹" . "¹") + ("²" . "²") + ("³" . "³") + ("&sqrt;" . "√") + ("&increment;" . "∆") + ("&infty;" . "∞") + ("∑" . "∑") + ("±" . "±") + ("&bulletop;" . "∙") + ("&partial;" . "∂") + ("&neg;" . "¬") + + ;; Currency symbols + ("¤cy;" . "¤") + ("$" . "$") + ("€" . "€") + ("£s;" . "£") + ("¥" . "Â¥") + ("¢" . "¢")))) diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm index ecd67e5b12..ec0ff1e37f 100644 --- a/scm/define-grob-properties.scm +++ b/scm/define-grob-properties.scm @@ -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, diff --git a/scm/define-markup-commands.scm b/scm/define-markup-commands.scm index 6ac78bac77..4b2aff5324 100644 --- a/scm/define-markup-commands.scm +++ b/scm/define-markup-commands.scm @@ -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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/scm/lily.scm b/scm/lily.scm index 193bf5df77..feec950c45 100644 --- a/scm/lily.scm +++ b/scm/lily.scm @@ -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 index 0000000000..3322c0e1b7 --- /dev/null +++ b/scm/text.scm @@ -0,0 +1,29 @@ +;;;; This file is part of LilyPond, the GNU music typesetter. +;;;; +;;;; Copyright (C) 2011 Bertrand Bordage +;;;; +;;;; 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 . + + +(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)))