UPDATE July 24, 2010: This post is now totally obsolete. See this post instead.
Recently, I’ve realized that the Autolily script I made was just one solution to a larger class of problems — that of calling a specific program on a target source/text file repeatedly every time you change the source. So, I’ve modified it slightly to make it accept any program name, so that the general format is: autocall [program] [file]. The source code is below:
#!/usr/bin/ruby #===============================================================================================================# # Program name: Autocall # # Author: Shinobu (zuttobenkyou.wordpress.com) # # Date: March 2010 # # LICENSE: PUBLIC DOMAIN # # # # This program takes 2 or 3 arguments; the first 2 is the command and file, while the third optional arg is the # # delay b/n each possible execution of the command. By default this delay is 1 second (it checks if the file has# # been modified every second) # # # # Place this script somewhere, like in ~/scripts # # Then, open up a terminal and call it like so: ~/scripts/autocall.rb [program] [file] # # # # You might want to do a "sudo ln -s" of autocall.rb to one of your system's $PATH directories (e.g., /usr/bin) # # to avoid typing out the path to autocall.rb every time you use it. Continuing the example from above, # # something like "sudo ln -s ~/scripts/autocall.rb /usr/bin/autocall" should do (make sure that # # /usr/bin/autocall does not exist already, as the above comman will overwrite that file if it exists). # # # # Now you can just do: # # # # autocall [command] [file] # # # # from anywhere in your system! # # # # To exit, press CTRL-C. # #===============================================================================================================# if ARGV.size > 1 file_data_orig = "" call = ARGV.shift file = ARGV.shift delay = 1 if ARGV.size > 0 delay = ARGV.shift.to_i end pathsize = file.split("/").size ls_call = "ls --full-time" # make sure that the "file" variable is a filename, and not mixed with its path if pathsize > 1 path_to_file = file.split("/").first(pathsize - 1).join("/") file = file.split("/").last ls_call << " #{path_to_file}" # modify our `ls` command to reflect relative location of file end `#{ls_call}`.split("\n").each do |line| if line.split(/\s/).last == file file_data_orig = line break end end file_data_new = "" # enter infinite loop -- keep compiling the given file if it has changed in the past 1 second while true # detect the file size and also timestamp lsarr = `#{ls_call}`.split("\n") lsarr.shift # get rid of the first line, since that is the size of all the files in the directory # find our file from ls's output! lsarr.each do |line| if line.split(/\s/).last == file file_data_new = line break end end # if there is any change detected, run given command on it if file_data_orig != file_data_new puts "\n\e[1;38;5;226mautocall: change detected @ #{Time.now.ctime} in file `#{file}'; invoking `#{call}'...\e[0m\n" if pathsize > 1 `#{call} "#{path_to_file}/#{file}"` else `#{call} "#{file}"` end file_data_orig = file_data_new end sleep delay end else puts "Usage: autocall [command] [file]\n" end
I can think of at least 1 other time you would want to use this script aside from editing LilyPond files — when editing LaTeX files. For me, I use currently use autocall to call a program that converts text files intelligently to HTML files. You could further edit the source to let it pass along command line options to autocall as well, and not just the program name (I will probably do this myself if the situation presents itself in the future).