]> git.donarmstrong.com Git - lilypond.git/blobdiff - Documentation/contributor/programming-work.itexi
Docs-fr: first translation of new website
[lilypond.git] / Documentation / contributor / programming-work.itexi
index bff7bbf47125137b914fa0875a97f85c2b681852..e62abc3f5712a2084f6d4e14dc1667d190967171 100644 (file)
 * Code style::
 * Debugging LilyPond::
 * Adding or modifying features::
+* Iterator tutorial::
+* Engraver tutorial::
+* Callback tutorial::
+* LilyPond scoping::
 @end menu
 
 @node Overview of LilyPond architecture
@@ -49,14 +53,16 @@ context(s).
 
 The final stage of LilyPond processing is @emph{translation}.  During
 translation, music events are prepared for graphical or midi output.  The
-translation step is accomplished by translators or engravers (the distinction
-is unclear).
+translation step is accomplished by the polymorphic base class Translator
+through its two derived classes: Engraver (for graphical output) and
+Performer (for midi output).
 
-Translators are defined in C++ files named *-engraver.cc.  In *-engraver.cc, a
-C++ class of Engraver type is created.  The Engraver is also declared as a
-translator.  Much of the work of translating is handled by Scheme functions,
+Translators are defined in C++ files named *-engraver.cc and *-performer.cc.
+Much of the work of translating is handled by Scheme functions,
 which is one of the keys to LilyPond's exceptional flexibility.
 
+@sourceimage{architecture-diagram,,,png}
+
 
 @node LilyPond programming languages
 @section LilyPond programming languages
@@ -79,6 +85,12 @@ documented in the
 @uref{http://www.gnu.org/software/guile/manual/html_node/index.html, GUILE
   Reference Manual}.
 
+@subsection Flex
+
+The LilyPond lexer is implemented in Flex, an implementation of the Unix lex
+lexical analyser generator.  Resources for Flex can be found
+@uref{http://flex.sourceforge.net/, here}.
+
 @subsection GNU Bison
 
 The LilyPond parser is implemented in Bison, a GNU parser generator.  The
@@ -95,7 +107,8 @@ documentation and the website.  GNU Make documentation is available at
 
 @subsection GUILE or Scheme
 
-GUILE is the dialect of Scheme that is used as LilyPond's extension language.  Many extensions to LilyPond are written entirely in GUILE.  The
+GUILE is the dialect of Scheme that is used as LilyPond's extension language.
+Many extensions to LilyPond are written entirely in GUILE.  The
 @uref{http://www.gnu.org/software/guile/manual/html_node/index.html,
 GUILE Reference Manual} is available online.
 
@@ -248,20 +261,6 @@ This will initiate a search of the remote git repository.
 
 @node Code style
 @section Code style
-@c email to wl@gnu.org when I get here.
-
-@warning{this is pending some confirmation on -devel.  July 2009 -gp}
-
-Command-line script to format stuff with emacs:
-
-@example
-#!/bin/sh
-emacs $1 -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer
-@end example
-
-(that's all on one line)
-
-Save it as a shell script, then run on the file(s) you modified.
 
 @menu
 @end menu
@@ -331,6 +330,85 @@ If you like using font-lock, you can also add this to your
                     ))
 @end verbatim
 
+Some source files may not currently have proper indenting.  If this
+is the case, it is desirable to fix the improper indenting when the
+file is modified, with the hope of continually improving the code.
+
+@subsection Indenting files with emacs in script mode
+
+@c email to wl@gnu.org when I get here.
+
+@warning{this is pending some confirmation on -devel.  July 2009 -gp}
+
+Command-line script to format stuff with emacs:
+
+@example
+#!/bin/sh
+emacs $1 -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer
+@end example
+
+(that's all on one line)
+
+Save it as a shell script, then run on the file(s) you modified.
+
+@subsection Indenting with vim
+
+Although emacs indentation is the LilyPond standard, acceptable
+indentation can usually be accomplished with vim.  Some hints for
+vim are as follows:
+
+A workable .vimrc:
+
+@verbatim
+set cindent
+set smartindent
+set autoindent
+set expandtab
+set softtabstop=2
+set shiftwidth=2
+filetype plugin indent on
+set incsearch
+set ignorecase smartcase
+set hlsearch
+set confirm
+set statusline=%F%m%r%h%w\ %{&ff}\ %Y\ [ASCII=\%03.3b]\ [HEX=\%02.2B]\ %04l,%04v\ %p%%\ [LEN=%L]
+set laststatus=2
+set number
+" Remove trailing whitespace on write
+autocmd BufWritePre * :%s/\s\+$//e
+@end verbatim
+
+With this .vimrc, files can be reindented automatically by highlihting
+the lines to be indented in visual mode (use V to enter visual mode)
+and pressing =.
+
+A scheme.vim file will help improve the indentation.  This one
+was suggested by Patrick McCarty.  It should be saved in
+~/.vim/after/syntax/scheme.vim.
+
+@verbatim
+" Additional Guile-specific 'forms'
+syn keyword schemeSyntax define-public define* define-safe-public
+syn keyword schemeSyntax use-modules define-module
+syn keyword schemeSyntax defmacro-public define-macro
+syn keyword schemeSyntax define-markup-command
+syn keyword schemeSyntax define-markup-list-command
+syn keyword schemeSyntax let-keywords* lambda* define*-public
+syn keyword schemeSyntax defmacro* defmacro*-public
+
+" All of the above should influence indenting too
+set lw+=define-public,define*,define-safe-public,use-modules,define-module
+set lw+=defmacro-public,define-macro
+set lw+=define-markup-command,define-markup-list-command
+set lw+=let-keywords*,lambda*,define*-public,defmacro*,defmacro*-public
+
+" These forms should not influence indenting
+set lw-=if
+set lw-=set!
+
+" Try to highlight all ly: procedures
+syn match schemeFunc "ly:[^) ]\+"
+@end verbatim
 
 @subsection Classes and Types
 
@@ -364,6 +442,28 @@ We reject broken-in-advance on principle.
 
 @subsection Naming
 
+Variable names should be complete words, rather than abbreviations.
+For example, it is preferred to use @code{thickness} rather than
+@code{th} or @code{t}.
+
+Multi-word variable names in C++ should have the words separated
+by the underscore character (@q{_}).
+
+Multi-word variable names in Scheme should have the words separated
+by a hyphen (@q{-}).
+
+@subsection Comments
+
+Comments may not be needed if descriptive variable names are used
+in the code and the logic is straightforward.  However, if the
+logic is difficult to follow, and particularly if non-obvious
+code has been included to resolve a bug, a comment describing
+the logic and/or the need for the non-obvious code should be included.
+
+There are instances where the current code could be commented better.
+If significant time is required to understand the code as part of
+preparing a patch, it would be wise to add comments reflecting your
+understanding to make future work easier.
 
 @subsection Messages
 
@@ -391,7 +491,7 @@ Every message to the user should be localized (and thus be marked
 for localization). This includes warning and error messages.
 
 @item
-Don't localize/gettextify:
+Do not localize/gettextify:
 
 @itemize
 @item
@@ -409,7 +509,7 @@ output strings (PostScript, TeX, etc.)
 @end itemize
 
 @item
-Messages to be localised must be encapsulated in `_ (STRING)' or
+Messages to be localized must be encapsulated in `_ (STRING)' or
 `_f (FORMAT, ...)'. E.g.:
 
 @example
@@ -522,7 +622,7 @@ _f ("Huh?  Not a Request: `%s'.  Ignoring.", request)
 @end example
 
 @item
-Do not modularise too much; words frequently cannot be translated
+Do not modularize too much; words frequently cannot be translated
 without context. It is probably safe to treat most occurences of
 words like stem, beam, crescendo as separately translatable words.
 
@@ -668,7 +768,7 @@ in the .ly file:
 
 @example
 #(module-define! (resolve-module '(guile-user))
-    'lilypond-module (current-module))
+                 'lilypond-module (current-module))
 @end example
 
 Second, place a Scheme function in the .ly file that gives an interactive Guile
@@ -721,11 +821,11 @@ The compilation of the .ly file will then continue.
 When a new feature is to be added to LilyPond, it is necessary to
 ensure that the feature is properly integrated to maintain
 its long-term support.  This section describes the steps necessary
-for feature addition.
+for feature addition and modification.
 
 @subsection Write the code
 
-You should create a new git branch for writing the code, as that
+You should probably create a new git branch for writing the code, as that
 will separate it from the master branch and allow you to continue
 to work on small projects related to master.
 
@@ -748,29 +848,6 @@ multiple-issue regression test.
 Use existing regression tests as templates to demonstrate the type of
 header information that should be included in a regression test.
 
-@subsection Write documentation
-
-Although it is not required, it is helpful if the developer can
-write relevant material for inclusion in the Notation Reference.
-If the developer does not feel qualified to write the documentation,
-a documentation editor will be able to write it from the regression
-tests.
-
-If the modification changes the input syntax so that inline snippets in
-the documentation need to be changed, you will need to change the
-snippets in both the english version of the documentation and any
-translated versions.  If you do not change the snippets in all
-translations, older versions of the snippet may be included
-when the documentation is built.
-
-If lsr snippets need to be changed, the snippet should be copied to
-@file{Documentation/snippets/new} and modified there.  The portions of
-the snippet that are added by makelsr.py should be removed.  The changed
-snippet will then be included in all versions of the documentation.
-
-If non-snippet text is changed in the english documentation, no
-corresponding changes should be made in the translated documentation.
-
 @subsection Write convert-ly rule
 
 If the modification changes the input syntax, a convert-ly rule
@@ -784,19 +861,118 @@ of the file.  In some cases, this will not be possible, so the
 rule will simply point out to the user that the feature needs
 manual correction.
 
-@subsection Write NEWS entry
+@subsection Automatically update documentation, snippets, and regtests
+
+convert-ly should be used to update the documentation, the snippets,
+and the regression tests.  This not only makes the necessary syntax
+changes, it also tests the convert-ly rules.
+
+The automatic updating is a three step process.  First, be sure you
+are in the top-level source directory.  Then, for the
+documentation, do:
+
+@example
+find Documentation/ -name '*.itely' | xargs convert-ly -e --from @qq{@var{X.Y.Z}}
+@end example
+
+@noindent
+where @var{X.Y.Z} is the version number of the last released development
+version.
+
+Next, for the snippets, do:
+
+@example
+find Documentation/snippets/ -name '*.ly' | xargs convert-ly -e --from @qq{@var{X.Y.Z}}
+@end example
+
+Finally, for the regression tests, do:
 
-An entry should be added to the NEWS file to describe the feature
-changes to be implemented.  This is especially important for changes
-that change input file syntax.
+@example
+find input/regression/ -name '*.ly' | xargs convert-ly -e --from @qq{@var{X.Y.Z}}
+
+@end example
 
-Hints for NEWS file entries are given at the top of the NEWS file.
+@subsection Manually update documentation, snippets, and regtests
+
+Where the convert-ly rule is not able to automatically update the inline
+lilypond code in the documentation (i.e. if a NOT_SMART rule is used), the
+documentation must be manually updated.  The inline snippets that require
+changing must be changed in the English version of the docs and all
+translated versions.  If the inline code is not changed in the
+translated documentation, the old snippets will show up in the
+English version of the documentation.
+
+Where the convert-ly rule is not able to automatically update snippets
+in Documentation/snippets/, those snippets must be manually updated.
+Those snippets should be copied to Documentation/snippets/new.  The
+comments at the top of the snippet describing its automatice generation
+should be removed.  All translated texidoc strings should be removed.
+The comment @qq{% begin verbatim} should be removed.  The syntax of
+the snippet should then be manually edited.
+
+Where snippets in Documentation/snippets are made obsolete, the snippet
+should be copied to Documentation/snippets/new.  The comments and
+texidoc strings should be removed as described above.  Then the body
+of the snippet should be changed to:
 
-New entries in NEWS go at the top of the file.
+@example
+\markup @{
+  This snippet is deprecated as of version X.Y.Z and
+  will be removed from the documentation.
+@}
+@end example
 
-The NEWS entry should be written to show how the new change
+@noindent
+where X.Y.Z is the version number for which the convert-ly rule was
+written.
+
+Update the snippet files by running:
+
+@example
+scripts/auxiliar/makelsr.py
+@end example
+
+Where the convert-ly rule is not able to automatically update regression
+tests, the regression tests in input/regression should be manually
+edited.
+
+Although it is not required, it is helpful if the developer
+can write relevant material for inclusion in the Notation
+Reference.  If the developer does not feel qualified to write
+the documentation, a documentation editor will be able to
+write it from the regression tests.  The text that is added to
+or removed from the documentation should be changed only in
+the English version.
+
+@subsection Edit changes.tely
+
+An entry should be added to Documentation/changes.tely to describe
+the feature changes to be implemented.  This is especially important
+for changes that change input file syntax.
+
+Hints for changes.tely entries are given at the top of the file.
+
+New entries in changes.tely go at the top of the file.
+
+The changes.tely entry should be written to show how the new change
 improves LilyPond, if possible.
 
+@subsection Verify successful build
+
+When the changes have been made, successful completion must be
+verified by doing
+
+@example
+make all
+make doc
+@end example
+
+When these commands complete without error, the patch is
+considered to function successfully.
+
+Developers on Windows who are unable to build LilyPond should
+get help from a Linux or OSX developer to do the make tests.
+
 @subsection Verify regression test
 
 In order to avoid breaking LilyPond, it is important to verify that
@@ -806,28 +982,64 @@ the regression tests all succeed.  This process is described in
 @subsection Post patch for comments
 
 For any change other than a minor change, a patch set should be
-posted on Rietveld for comment.
+posted on @uref{http://codereview.appspot.com/, Rietveld} for comment.
+This requires the use of an external package, git-cl, and an email
+account on Google.
+
+git-cl is installed by:
+
+@example
+git clone git://neugierig.org/git-cl.git
+@end example
 
-The patch set is posted by issuing the following command, after
-first committing all changes:
+Then, add the git-cl directory to your PATH, or create a
+symbolic link to the git-cl and upload.py in one of your
+PATH directories (like usr/bin).  git-cl is then
+configured by entering the command
 
 @example
-git-cl upload <reference SHA1 ID>
+git cl config
+@end example
+
+@noindent
+in the LilyPond git directory and answering the questions that
+are asked.  If you do not understand the question answer with just
+a newline (CR).
+
+The patch set is posted to Rietveld as follows.  Ensure your changes
+are committed in a separate branch, which should differ from the
+reference branch to be used by just the changes to be uploaded.
+If the reference branch is to be origin/master, ensure this is
+up-to-date.  If necessary, use git rebase to rebase the branch
+containing the changes to the head of origin/master.  Finally,
+check out branch with the changes and enter the command:
+
+@example
+git cl upload <reference SHA1 ID>
 @end example
 
 @noindent
 where <reference SHA1 ID> is the SHA1 ID of the commit to be used
-as a reference source for the patch (generally, this will be the
-SHA1 ID of origin/master).
+as a reference source for the patch.  Generally, this will be the
+SHA1 ID of origin/master, and in that case the command
+
+@example
+git cl upload origin/master
+@end example
+
+@noindent
+can be used.
 
-After prompting for an email and a password, the patch set will be
-posted to Rietveld.
+After prompting for your Google email address and password, the
+patch set will be posted to Rietveld.
 
-An email should then be sent to lilypond-devel, with a subject line
+You should then announce the patch by sending
+an email to lilypond-devel, with a subject line
 starting with PATCH:, asking for comments on the patch.
 
 As revisions are made in response to comments, successive patch sets
-for the same issue can be uploaded by reissuing the git-cl command.
+for the same issue can be uploaded by reissuing the git-cl command
+with the modified branch checked out.
 
 @subsection Push patch
 
@@ -847,7 +1059,218 @@ to the left of the issue name.
 
 If the changes were in response to a feature request on the Google
 issue tracker for LilyPond, the author should change the status to
-@q{Fixed_x_y_z} where the patch was fixed in version x.y.z.  If
+Fixed and a tag @q{fixed_x_y_z} should be added, where the patch was
+fixed in version x.y.z.  If
 the author does not have privileges to change the status, an email
 should be sent to bug-lilypond requesting the BugMeister to change
 the status.
+
+@node Iterator tutorial
+@section Iterator tutorial
+
+FIXME -- this is a placeholder for a tutorial on iterators
+
+Iterators are routines written in C++ that process music expressions
+and sent the music events to the appropriate engravers and/or
+performers.
+
+@node Engraver tutorial
+@section Engraver tutorial
+
+FIXME -- This is a placeholder for a tutorial on how engravers work.
+
+Engravers are C++ classes that catch music events and
+create the appropriate grobs for display on the page.  Though the
+majority of engravers are responsible for the creation of a single grob,
+in some cases (e.g. @code{New_fingering_engraver}), several different grobs
+may be created.
+
+@subsection Useful methods for information processing
+
+An engraver inherits the following public methods from the Translator
+base class, which can be used to process listened events and acknowledged
+grobs:
+
+@itemize
+@item @code{virtual void initialize ()}
+@item @code{void start_translation_timestep ()}
+@item @code{void process_music ()}
+@item @code{void process_acknowledged ()}
+@item @code{void stop_translation_timestep ()}
+@item @code{virtual void finalize ()}
+@end itemize
+
+These methods are listed in order of translation time, with
+@code{initialize ()} and @code{finalize ()} bookending the whole
+process.  @code{initialize ()} can be used for one-time initialization
+of context properties before translation starts, whereas
+@code{finalize ()} is often used to tie up loose ends at the end of
+translation: for example, an unterminated spanner might be completed
+automatically or reported with a warning message.
+
+@subsection Translation process
+
+At each timestep in the music, translation proceeds by calling the
+following methods in turn:
+
+@code{start_translation_timestep ()} is called before any user information enters
+the translators, i.e., no property operations (\set, \override, etc.) or events
+have been processed yet.
+
+@code{process_music ()} and @code{process_acknowledged ()} are called after events
+have been heard, or grobs have been acknowledged.  The latter tends to be used
+exclusively with engravers which only acknowledge grobs, whereas the former is
+the default method for main processing within engravers.
+
+@code{stop_translation_timestep ()} is called after all user information has been
+processed prior to beginning the translation for the next timestep.
+
+@subsection Preventing garbage collection for SCM member variables
+
+In certain cases, an engraver might need to ensure private Scheme variables
+(with type SCM) do not get swept away by Guile's garbage collector: for example,
+a cache of the previous key signature which must persist persist between timesteps.
+The method @code{virtual derived_mark () const} can be used in such cases to mark
+such objects as follows:
+
+@example
+Engraver_name::derived_mark ()
+@{
+  scm_gc_mark (private_scm_member_)
+@}
+@end example
+
+
+@subsection Listening to music events
+
+External interfaces to to the engraver are implemented by protected
+macros including one or more of the following:
+
+@itemize
+@item @code{DECLARE_TRANSLATOR_LISTENER (event_name)}
+@item @code{IMPLEMENT_TRANSLATOR_LISTENER (Engraver_name, event_name)}
+@end itemize
+
+@noindent
+where @var{event_name} is the type of event required to provide the
+input the engraver needs and @var{Engraver_name} is the name of the
+engraver.
+
+Following declaration of a listener, the method is implemented as follows:
+
+@example
+IMPLEMENT_TRANSLATOR_LISTENER (Engraver_name, event_name)
+void
+Engraver_name::listen_event_name (Stream event *event)
+@{
+  ...body of listener method...
+@}
+@end example
+
+@subsection Acknowledging grobs
+
+Some engravers also need information from grobs as they are created
+and as they terminate.  The mechanism and methods to obtain this
+information are set up by the macros:
+
+@itemize
+@item @code{DECLARE_ACKNOWLEDGER (grob_interface)}
+@item @code{DECLARE_END_ACKNOWLEDGER (grob_interface)}
+@end itemize
+
+where @var{grob_interface} is an interface supported by the
+grob(s) which should be acknowledged.  For example, the following
+code would declare acknowledgers for a @code{NoteHead} grob (via the
+@code{note-head-interface}) and any grobs which support the
+@code{side-position-interface}:
+
+@example
+@code{DECLARE_ACKNOWLEDGER (note_head)}
+@code{DECLARE_ACKNOWLEDGER (side_position)}
+@end example
+
+The @code{DECLARE_END_ACKNOWLEDGER ()} macro sets up a spanner-specific
+acknowledger which will be called whenever a spanner ends.
+
+Following declaration of an acknowledger, the method is coded as follows:
+
+@example
+void
+Engraver_name::acknowledge_interface_name (Grob_info info)
+@{
+  ...body of acknowledger method...
+@}
+@end example
+
+@subsection Engraver declaration/documentation
+
+An engraver must have a public macro
+
+@itemize
+@item @code{TRANSLATOR_DECLARATIONS (Engraver_name)}
+@end itemize
+
+@noindent
+where @code{Engraver_name} is the name of the engraver.  This
+defines the common variables and methods used by every engraver.
+
+At the end of the engraver file, one or both of the following
+macros are generally called to document the engraver in the
+Internals Reference:
+
+@itemize
+@item @code{ADD_ACKNOWLEDGER (Engraver_name, grob_interface)}
+@item @code{ADD_TRANSLATOR (Engraver_name, Engraver_doc,
+    Engraver_creates, Engraver_reads, Engraver_writes)}
+@end itemize
+
+@noindent
+where @code{Engraver_name} is the name of the engraver, @code{grob_interface}
+is the name of the interface that will be acknowledged,
+@code{Engraver_doc} is a docstring for the engraver,
+@code{Engraver_creates} is the set of grobs created by the engraver,
+@code{Engraver_reads} is the set of properties read by the engraver,
+and @code{Engraver_writes} is the set of properties written by
+the engraver.
+
+@node Callback tutorial
+@section Callback tutorial
+
+FIXME -- This is a placeholder for a tutorial on callback functions.
+
+@node LilyPond scoping
+@section LilyPond scoping
+
+The Lilypond language has a concept of scoping, ie you can do
+
+@example
+foo = 1
+
+#(begin
+   (display (+ foo 2)))
+@end example
+
+@noindent with @code{\paper}, @code{\midi} and @code{\header} being
+nested scope inside the @file{.ly} file-level scope.  @w{@code{foo = 1}}
+is translated in to a scheme variable definition.
+
+This implemented using modules, with each scope being an anonymous
+module that imports its enclosing scope's module.
+
+Lilypond's core, loaded from @file{.scm} files, is usually placed in the
+@code{lily} module, outside the @file{.ly} level.  In the case of
+
+@example
+lilypond a.ly b.ly
+@end example
+
+@noindent
+we want to reuse the built-in definitions, without changes effected in
+user-level @file{a.ly} leaking into the processing of @file{b.ly}.
+
+The user-accessible definition commands have to take care to avoid
+memory leaks that could occur when running multiple files.  All
+information belonging to user-defined commands and markups is stored in
+a manner that allows it to be garbage-collected when the module is
+dispersed, either by being stored module-locally, or in weak hash
+tables.