Skip to content

Instantly share code, notes, and snippets.

@ttscoff
Created January 25, 2012 15:05
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ttscoff/1676667 to your computer and use it in GitHub Desktop.
Save ttscoff/1676667 to your computer and use it in GitHub Desktop.
Watch a Scrivener project for changes and update Marked.app
#!/usr/bin/env ruby
# scrivwatch.rb by Brett Terpstra, 2011
# Modifications to merge into one file for Markdown viewing in Marked by BooneJS, 2012
# Modified to use REXML and add titles by Brett Terpstra, 2012 <https://gist.github.com/1676667>
#
# Watch a Scrivener project for changes and update a preview file for Marked
# Usage: scrivwatch.rb /path/to/document.scriv
# <http://markedapp.com>
require 'fileutils'
require 'rexml/document'
def get_children(ele,path,files,depth)
ele.elements.each('*/BinderItem') do |child|
id = child.attributes["ID"]
title = child.elements.to_a[0].text
file = "#{path}/Files/Docs/#{id}.rtf"
filepath = File.exists?(file) ? file : false
files << { 'path' => filepath, 'title' => title, 'depth' => depth }
get_children(child,path,files,depth+1)
end
end
# Take the path to the scrivener file and open the internal XML file.
def get_rtf_file_array(scrivpath)
scrivpath = File.expand_path(scrivpath)
files = []
scrivx = File.basename("#{scrivpath}", ".scriv") + ".scrivx"
doc = REXML::Document.new File.new("#{scrivpath}/#{scrivx}")
drafts = nil
doc.elements.each('ScrivenerProject/Binder/BinderItem') do |ele|
if ele.attributes['ID'] == "0"
get_children(ele,scrivpath,files,1)
end
end
return files
end
trap("SIGINT") { exit }
if ARGV.length != 1 || ARGV[0] !~ /\.scriv\/?$/
puts "Usage: scrivwatch.rb /path/to/document.scriv"
exit
end
marked_note = File.expand_path("~/Marked Preview.md")
FileUtils.touch(marked_note)
%x{open -a /Applications/Marked.app "#{marked_note}"}
path = File.expand_path(ARGV[0].gsub(/\/$/,''))
first = true
while true do # repeat infinitely
notetext = ""
files = get_rtf_file_array(path)
new_hash = files.collect {|f| [ f['path'], File.stat(f['path']).mtime.to_i ] if f['path'] } # create a hash of timestamps
hash ||= new_hash
diff_hash = new_hash - hash # check for changes
unless first==false and diff_hash.empty? # if changes were found in the timestamps
first = false
hash = new_hash
# All attempts to pass more than 1 file to textutil failed. Do it one-at-a-time.
files.each{ |f|
note = f['path'] ? %x{/usr/bin/textutil -convert txt -stdout "#{f['path']}"} : ''
leader = ""
f['depth'].times { leader += "#" }
notetext = notetext + "#{leader} #{f['title']}\n\n" + note + "\n\n"
}
# write the result to the preview file
watch_note = File.new("#{marked_note}",'w')
watch_note.puts notetext
watch_note.close
end
sleep 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment