#!/usr/bin/perl

# This program implements a basic IDE loop for prgramming LilyPond.
#
# It opens the file in the editor, runs lilypond and opens the PDF in
# a viewer.
#
# It then monitors the source file. If it changes, LilyPond is rerun
# and the PDF view updated.
#
# This works with GNU Emacs 22.x and the Gnome PDF viewer 'evince'.
# But is may work with other tools as well.
#
# A companion script textedit-url-handler can be used with LilyPond's
# point'n'click feature: When clicking on a note or syllable in the
# PDF document, the editor will show the associated source file at the
# exact location.
#
# Copyright 2009 Johan Vromans. All rights reseved.
# This program is public domain and may be used, changed and
# distributed at will, provided you leave the initial copyright notice
# in place.

use strict;
use warnings;

################ Set up ################

# Must have one arg: the lilypond source file.
die("Usage: ide file.ly") unless @ARGV >= 1;

# Other files to watch.
my @files = @ARGV;

# Make PDF file name.
die("Usage: ide file.ly") unless $files[0] =~ /^(.+)\.ly$/;
my $pdf = "$1.pdf";

# Get current source file times.
my @ages = get_filetimes(@files);

# Prepare initial PDF, if necessary.
if ( ! -s $pdf or (get_filetimes($pdf))[0] < $ages[0] ) {
    run_lilypond($files[0]) unless -s $pdf;
}
die("No PDF from $files[0]?\n") unless -s $pdf;

# Open file in editor. Assumes intelligent client.
run_editor($_) foreach reverse @files;

# Open file in viewer.
run_pdfviewer($pdf);

################ Loop ################

while ( 1 ) {
    my @ts = get_filetimes(@files);
    next if "@ages" eq "@ts";

    # Re-run LilyPond and generate a new PDF.
    run_lilypond($files[0]);

    # Refresh the view in Evince.
    # Newer versions of Evince seem to refresh the view automatically
    # when the PDF document changes. If your Evince does this, comment
    # out the next line:
    # run_pdfviewer($pdf);

    @ages = @ts;
}
continue {
    sleep(1);
}

################ Subroutines ################

sub get_filetimes {
    return map { -C $_ } @_;
}

sub run_lilypond {
    my $file = shift;
    system( "lilypond", $file );
}

sub run_pdfviewer {
    my $file = shift;
    system( "evince $file &" );
}

sub run_editor {
    my $file = shift;
    system( "emacsclient", "--no-wait", $file );
}

################  ################
