<<< Date Index >>>     <<< Thread Index >>>

Re: 1.5.9: Feature request, ifdef



* On 2005.02.20, in <20050220125951.GB3050@xxxxxxxxxxxxxxxxxxxxx>,
*       "Mads Laursen" <mutt@xxxxxxxxx> wrote:
> 
> out of date mutt-versions. With a facility to test for features, one
> can write a configuration that takes advantage of features, while
> still working on older/standard installations.

I agree that this kind of functionality is useful. I'm not as concerned
with whether it goes into mutt -- this function is available without
code changes -- but I also think that code changes are the best way to
make it accessible to casual or inexperienced users.

I'm using m4 to preprocess my muttrc. I've been meaning for a while to
post how I do this, but I'm not sure I'll ever get around to cleaning
everything up enough to post. I can post part of it now, though.

First I'm going to describe what I'm doing now, and then I'll talk about
a couple of suggestions.

What I do now:

1. My .muttrc is a quick one-liner:
   source "~/.mutt/muttrc.sh|"

   This means that my entire mutt configuration is read from the stdout
   of the muttrc.sh script.

2. The muttrc.sh script is attached. This egregious program runs "mutt
   -v" to generate a list of features and patches. It uses sed to
   transform that into a list of -DSYMBOL and -UNOTSYMBOL expressions.
   These expressions are passed as arguments to a preprocessor. I use
   m4, but cpp (or gcc -E) would work, as would any other filter that
   accepts variables as -D and -U arguments.

3. The muttrc.sh also copies environment variables that begin with
   MUTT_ as -D parameters, so that you can pass arbitrary information
   to mutt's dynamic configuration from your shell startup, or
   whatever. It passes the local hostname too, and also the value of
   the $DOMAIN variable so that I can choose a different configuration
   macroscopically depending on what environment I'm running in.

4. The m4/cpp preprocessor reads my muttrc from ~/.mutt/muttrc.m4. This
   file is a plain old muttrc file, but with some m4 macro expansions,
   conditionals, etc. to adapt my configuration to the features I have
   enabled in mutt and to the location I'm running it from. The result
   is tuned for wherever I'm running it.

Here's the command that muttrc.sh generates to read my configuration.
This is created dynamically, each time I run mutt, almost all based on
"mutt -v" output.

m4 -s -DMUTTDIR=.mutt -DMUTT_DOMAIN=uchicago.edu -DMUTT_HOSTNAME=monkey 
'-DVERSION=156' -UDOMAIN -DDEBUG -UHOMESPOOL -UUSE_SETGID -DUSE_DOTLOCK 
-UDL_STANDALONE -DUSE_FCNTL -UUSE_FLOCK -DUSE_POP -DUSE_IMAP 
-UIMAP_EDIT_THREADS -UUSE_GSS -DUSE_SSL -UUSE_SASL -UUSE_SASL2 -DHAVE_REGCOMP 
-UUSE_GNU_REGEX -DCOMPRESSED -DHAVE_COLOR -UHAVE_START_COLOR -UHAVE_TYPEAHEAD 
-UHAVE_BKGDSET -UHAVE_CURS_SET -UHAVE_META -UHAVE_RESIZETERM 
-DCRYPT_BACKEND_CLASSIC_PGP -DCRYPT_BACKEND_CLASSIC_SMIME -UCRYPT_BACKEND_GPGME 
-UBUFFY_SIZE -UEXACT_ADDRESS -DSUN_ATTACHMENT -DENABLE_NLS -ULOCALES_HACK 
-DHAVE_WC_FUNCS -DHAVE_LANGINFO_CODESET -DHAVE_LANGINFO_YESEXPR -DHAVE_ICONV 
-DICONV_NONTRANS -UHAVE_LIBIDN -DHAVE_GETSID -DHAVE_GETADDRINFO 
'-DISPELL="/opt/bin/ispell"' '-DSENDMAIL="/usr/lib/sendmail"' 
'-DMAILPATH="/var/mail"' 
'-DPKGDATADIR="/opt/pkgs/mutt_cvs-0.20041011/share/mutt"' 
'-DSYSCONFDIR="/opt/pkgs/mutt_cvs-0.20041011/etc"' '-DEXECSHELL="/bin/sh"' 
-UMIXMASTER -DPATCH_ats_parent_match=1 -DPATCH_ats_parent_match_1 
-DPATCH_dgc_setenv=1 -DPATCH_dgc_setenv_1 -DPATCH_dgc_softfill=2 
-DPATCH_dgc_softfill_2 -DPATCH_dgc_flagsafe=1 -DPATCH_dgc_flagsafe_1 
-DPATCH_dgc_fmtpipe=1 -DPATCH_dgc_fmtpipe_1 -DPATCH_dgc_markmsg=2 
-DPATCH_dgc_markmsg_2 -DPATCH_dgc_deepif=1 -DPATCH_dgc_deepif_1 
-DPATCH_dgc_groupalts=2 -DPATCH_dgc_groupalts_2 -DPATCH_dgc_xlabel_ext=6 
-DPATCH_dgc_xlabel_ext_6 -DPATCH_6_rr= -DPATCH_6_rr_compressed 
-DPATCH_dgc_attach=5 -DPATCH_dgc_attach_5 -DPATCH_cd_pattern_broken=1 
-DPATCH_cd_pattern_broken_1 -DPATCH_cd_edit_threads=9 
-DPATCH_cd_edit_threads_9_2 -DPATCH_dgc_isalias=1 -DPATCH_dgc_isalias_1 
-DPATCH_ats_mark_old=1 -DPATCH_ats_mark_old_1 -DPATCH_ats_date_conditional=1 
-DPATCH_ats_date_conditional_1 -DMUTT_DATEEXP='%?[6M?%\?[7d\?%\\?[18h\\?%[ 
%H:%M]\\&%[%a %d]\\?\&%[%b %d]\?&%[%y%m%d]?' -DMUTT_SOFTFILL='%?H?*%H* ?%= 
s%?Y? [%Y&\%\?y\? \" \??%?X? {%X}?' .mutt/muttrc.m4

Note that the PATCH_* defines are defined in two different ways, for
the benefit of different kinds of preprocessor. For example, for
patch-1.5.6.dgc.xlabel_ext.6, the script creates
        PATCH_dgc_xlabel_ext=6
        PATCH_dgc_xlabel_ext_6

A preprocessor that can do math can make a condition like
        #if (PATCH_dgc_xlabel_ext >= 5)
          ...
        #endif

and a preprocessor that cannot can do (making up a syntax)
        @if PATCH_dgc_xlabel_ext_5 or PATCH_dgc_xlabel_ext_6
          ...
        @endif


A preprocessor feature is much more appealing to me as a way of getting
conditionality into mutt. It's more flexible than if[n]def alone. It
also lets you choose your language -- you can use m4 or cpp, or you can
use any other macro language you like as long as you can wrap it in
something that takes -D and -U arguments. Use XSLT, that works too. :)

The approach I use has worked fine for me for years, but I'm not
sure it's the best solution for the new user who wants/needs this
functionality -- especially if they need to set it up themselves. I see
a few solutions to that:

1. Include something like muttrc.sh with mutt, and make it available
   in the default configuration without any editing. For example,
   mutt could include muttrc.sh as /usr/local/bin/muttpp (for mutt
   preprocessor). Then, either:

   a. If a user wanted a preprocesed muttrc, he could rename ~/.muttrc
      to ~/.mutt/muttrc.pp and change ~/.muttrc to do the "source ...|"
      line.

   b. If mutt detects a ~/.muttrc.pp (or whatever) file, then it could
      automatically source it via /usr/local/bin/muttpp. This approach
      would require no extra configuration from the user, and doesn't
      really have any disadvantage over (a). I'd prefer it.

2. a. Provide a new configuration variable, $preprocessor. If it's
      set, then whenever mutt_open_read() receives a filename to open,
      it instead opens a filter (mutt_create_filter()) using the
      $preprocessor and the filename. This is completely transparent
      to the user, and seems the best-integrated approach to me. If
      $preprocessor is unset, then the file is opened as usual.

      (There is exactly one other use of mutt_open_read in 1.5.8. It's
      used to open the signature file, and actually that might be
      another nice use of the preprocessor.)

      This option might still require a user to install a .muttrc in
      order to set $preprocessor, and then to source another file, too,
      so it could be less convenient than (1a) or (1b). But it can also
      be set to a default in the system Muttrc, if that seems desirable
      to a system manager or a packager. Then it's zero-configuration
      for the end-user.

   b. As an extension to (2a), mutt could generate all the -D and -U
      tokens internally, obviating the muttrc.sh/muttpp script. This has
      some portability advantages, but it's arguably less flexible.

(1a) requires the least change in mutt -- just add a file to the
distribution and ensure that it's installed by the Makefile.

(1b) requires minor code change to detect another file at startup, and
respond differently.

(2a) is approximately the same in cost: it just detects whether
$preprocessor is set, and alters the way it reads that data.

(2b) would require some changes in the way that features and patches
are represented internally, so that the argv could be assembled for the
preprocessor command. But this wouldn't hard or risky, particularly.

Personally, my order of preference, then, would be (2a) or (2b), then
(1b), then (1a). I'm willing to do any patchwork to make any of these
happen, if it seems like a usable design to Thomas. Otherwise, feel free
to use this script on your own. :)

-- 
 -D.    dgc@xxxxxxxxxxxx                                  NSIT::ENSS

Attachment: muttrc.sh
Description: Bourne shell script