Initial import of rubberin.
This commit is contained in:
commit
91b56eca61
177
rubberin
Executable file
177
rubberin
Executable file
|
@ -0,0 +1,177 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# rubberin - a rubber wrapper using inotify
|
||||
#
|
||||
# Copyright (C) 2007 Paul van Tilburg <paul@luon.net>
|
||||
#
|
||||
# This script can assist the authoring of LaTeX documents. It acts as an
|
||||
# drop-in replacement for rubber. While rubber would just perform a
|
||||
# compilation of the LaTeX file, rubberin will perform a compilation (using
|
||||
# rubber) each time it detects a modification in the LaTeX file or any of
|
||||
# its dependencies (include files, BibTeX files, image, etc.) until
|
||||
# rubberin is interrupted. Additionally, rubberin spawns a viewer to view
|
||||
# the result of the LaTeX compilation and forces it to reload every time
|
||||
# rubberin has recompiled the LaTeX file.
|
||||
#
|
||||
# This program 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 2 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WAR RANTY; 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 this p rogram; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
require 'getoptlong'
|
||||
require 'inotify'
|
||||
require 'pathname'
|
||||
|
||||
# Small necessary Pathname class extension.
|
||||
class Pathname
|
||||
def extname=(ext)
|
||||
raise "Invalid extension" unless ext.is_a? String and ext.match(/^\./)
|
||||
@path.sub!(/#{extname}$/, ext)
|
||||
end
|
||||
end
|
||||
|
||||
## Helper methods
|
||||
|
||||
# Print the usage.
|
||||
def usage
|
||||
puts "Usage: #{Program} [options]... [tex-file] [rubber-options]..."
|
||||
end
|
||||
|
||||
# Print the command line help.
|
||||
def help
|
||||
usage
|
||||
puts "Wrapper for rubber that facilitates automatic compiling and viewer updating"
|
||||
puts "when the input file or dependancy files are modified."
|
||||
puts
|
||||
puts "Available options:"
|
||||
puts " -d, --pdf produce a PDF file (via ps2pdf if used with -p)"
|
||||
puts " -h, --help display this help"
|
||||
puts " -p, --ps produce a PostScript file"
|
||||
puts "The options --pdf and --ps are passed to rubber like all options not listed above."
|
||||
end
|
||||
|
||||
# Compile the input file using the right options based on the mode.
|
||||
def compile(infile, mode)
|
||||
mode_opt = {:pdf => "--pdf",
|
||||
:ps => "--ps",
|
||||
:pspdf => "--ps --pdf"}[mode]
|
||||
params = ARGV.join(' ')
|
||||
err_file = infile.with_extname('err')
|
||||
|
||||
system "rubber --inplace #{mode_opt} #{params} #{infile} 2> #{err_file}"
|
||||
File.open(err_file) { |file| puts file.read }
|
||||
end
|
||||
|
||||
# Start the right viewer based on the mode.
|
||||
def view(infile, mode)
|
||||
case mode
|
||||
when :dvi
|
||||
exec "xdvi.bin", "-watchfile", "1",
|
||||
"-name", "xdvi", infile.with_extname('dvi')
|
||||
when :ps
|
||||
exec "evince", infile.with_extname('ps')
|
||||
when :pdf, :pspdf
|
||||
exec "evince", infile.with_extname('pdf')
|
||||
end
|
||||
end
|
||||
|
||||
# Reload the right viewer based on the mode.
|
||||
def reload(infile, mode)
|
||||
case mode
|
||||
when :ps
|
||||
system "evince", infile.with_extname('ps')
|
||||
when :pdf, :pspdf
|
||||
system "evince", infile.with_extname('pdf')
|
||||
end
|
||||
end
|
||||
|
||||
## Initialisation
|
||||
Program = File.basename $0
|
||||
Version = '0.4a'
|
||||
|
||||
# Parse the command line options.
|
||||
# Determine the compile mode from the options.
|
||||
mode = :dvi
|
||||
opts = GetoptLong.new(
|
||||
[ "--help", "-h", GetoptLong::NO_ARGUMENT ],
|
||||
[ "--ps", "-p", GetoptLong::NO_ARGUMENT ],
|
||||
[ "--pdf", "-d", GetoptLong::NO_ARGUMENT ])
|
||||
opts.ordering = GetoptLong::REQUIRE_ORDER
|
||||
opts.quiet = true
|
||||
opts.each do |opt, arg|
|
||||
case opt
|
||||
when "--help"
|
||||
help
|
||||
exit 0
|
||||
when "--ps"
|
||||
mode = :ps
|
||||
when "--pdf"
|
||||
mode = if mode == :ps then :pspdf
|
||||
else :pdf
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Get the input file from the arguments.
|
||||
if ARGV.length < 1
|
||||
usage
|
||||
exit 1
|
||||
else
|
||||
infile = Pathname.new(ARGV.shift)
|
||||
def infile.base
|
||||
self.basename(self.extname)
|
||||
end
|
||||
def infile.with_extname(ext)
|
||||
file = self.base
|
||||
file.extname = ".#{ext}"
|
||||
file
|
||||
end
|
||||
end
|
||||
|
||||
# Check the input file.
|
||||
begin
|
||||
File.open(infile) {}
|
||||
rescue => err
|
||||
puts "#{Program}: #{err}"
|
||||
exit 2
|
||||
end
|
||||
|
||||
# Find the dependancies of the input file using rubber-info and
|
||||
# do an initial run.
|
||||
files = `rubber-info --deps #{infile}`.chomp.split
|
||||
compile(infile, mode)
|
||||
|
||||
# Spawn a viewer based on the mode.
|
||||
viewer_pid = fork
|
||||
view(infile, mode) if not viewer_pid
|
||||
|
||||
# Handle signals.
|
||||
["INT", "TERM", "QUIT"].each do |sig|
|
||||
Signal.trap(sig) { Process.kill(sig, viewer_pid); exit }
|
||||
end
|
||||
# If xdvi exits, this program should exit too.
|
||||
Signal.trap("CLD") { puts "#{Program}: viewer exited, so will I!"; exit }
|
||||
|
||||
## Main event loop
|
||||
|
||||
# Add input file with dependancies to the watch list and start event loop.
|
||||
i = Inotify.new
|
||||
files.each do |file|
|
||||
i.add_watch(file, Inotify::MODIFY)
|
||||
end
|
||||
# Process the events, recompile and reload when necessary.
|
||||
i.each_event do |ev|
|
||||
puts "I: file #{ev.name} modified, compiling #{infile}..."
|
||||
compile(infile, mode)
|
||||
reload(infile, mode)
|
||||
end
|
Loading…
Reference in a new issue