mmd mmd-latex Print mmd-html mmd-odf mmd-pdf pandoc-docx pandoc-docbook pandoc-epub Yes ]]> <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb720\sa720\pardirnatural\qc\partightenfactor0 \f0\fs24 \cf0 <$Scr_H::1> \fs96 Attributes \fs24 <!$Scr_H::1>}]]> \fs96 Attributes \fs24 }]]> \fs96 Attributes \fs24 }]]> Yes No Yes <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb720\sa720\pardirnatural\qc\partightenfactor0 \f0\fs24 \cf0 <$Scr_H::1> \fs56 Attributes \fs24 <!$Scr_H::1>}]]> \fs56 Attributes \fs24 }]]> \fs56 Attributes \fs24 }]]> Yes No Yes <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb480\sa240\pardirnatural\qc\partightenfactor0 \f0\fs24 \cf0 <$ScrKeepWithNext><$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 <!$Scr_H::2>}]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> Yes No Yes — ]]> <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb480\sa240\pardirnatural\qc\partightenfactor0 \f0\fs24 \cf0 <$ScrKeepWithNext><$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 <!$Scr_H::2>}]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> Yes No Yes <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb480\sa240\pardirnatural\partightenfactor0 \f0\fs24 \cf0 <$ScrKeepWithNext><$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 <!$Scr_H::2>}]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> Yes No Yes <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb480\sa240\pardirnatural\partightenfactor0 \f0\fs24 \cf0 <$ScrKeepWithNext><$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 <!$Scr_H::2>}]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> Yes No Yes — ]]> <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sb480\sa240\pardirnatural\partightenfactor0 \f0\fs24 \cf0 <$ScrKeepWithNext><$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 <!$Scr_H::2>}]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> <$Scr_H::2> \f1\b\fs40 Attributes \f0\b0\fs24 }]]> Yes No <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 GretaTextPro-Regular;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 \f0\fs28 \cf0 Attributes}]]> Yes No Yes ]]> <![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 GretaTextPro-Regular;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 \f0\fs28 \cf0 Attributes}]]> Yes No Yes Yes Yes GretaTextPro-Regular Yes Yes No Spacing+Indents Yes 18.0 ]]> ]]> ]]> ]]> ]]> ]]> Yes Yes Yes Yes Yes No GretaTextPro-Regular Yes Yes Default Arabic Arabic Continuous Yes End Helvetica Yes Yes Yes No Comments Yes <span class="comment" title="<$cmt>"><$lnk></span> 1.0 1.0 1.0 1.0 Helvetica Helvetica Yes Yes -1
]]>
]]>
]]>
Yes Yes 0.042799 0.325744 0.003139 Yes Yes Yes .AppleSystemUIFont Courier Yes 600 <Extension>txt</Extension> </PlainText> <MMD> <MetaData> <Value IsProjectMetaDataPlaceholder="Yes"/> </MetaData> <CaptionStyleID>FFD9326A-EFB4-473F-8445-76B7B04E6188</CaptionStyleID> <AddClosingHashesToTitles>Yes</AddClosingHashesToTitles> <LaTeXDocumentClass>Memoir</LaTeXDocumentClass> <UsePandocSyntax>Yes</UsePandocSyntax> </MMD> <EBookSettings> <BaseFormat><![CDATA[{\rtf1\ansi\ansicpg1252\cocoartf2821 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 \f0\fs24 \cf0 Attributes}]]></BaseFormat> <CSSStylesFromDirectFormatting>Yes</CSSStylesFromDirectFormatting> <EndnotesTitle>Notes</EndnotesTitle> <EquationsAsMathML>Yes</EquationsAsMathML> <TablesAndLists> <TableStyle>Basic</TableStyle> <EpubListStyle>Basic</EpubListStyle> <KindleListStyle>Basic</KindleListStyle> <EpubBulletStyle>Basic</EpubBulletStyle> <KindleBulletStyle>Basic</KindleBulletStyle> </TablesAndLists> <ScriptSettings HasScriptFormatting="No"><![CDATA[.scene-heading {text-align:left; text-indent:0; margin: 12pt 0 0 0; text-transform:uppercase; font-family: monospace;} .action {text-align:left; text-indent:0; margin: 12pt 0 0 0; font-family: monospace;} .character {text-align:center; text-indent:0; margin: 12pt 0 0 0; text-transform:uppercase; font-family: monospace;} .parenthetical {text-align:center; text-indent:0; margin: 0 0 0 0; font-family: monospace;} .dialogue {text-align:left; text-indent:0; margin: 0 20% 0 20%; font-family: monospace;} .transition {text-align:right; text-indent:0; margin: 12pt 0 0 0; text-transform:uppercase; font-family: monospace;} .shot {text-align:left; text-indent:0; margin: 12pt 0pt 0pt 0pt; text-transform:uppercase; font-family: monospace;}]]></ScriptSettings> <PandocSettings> <Version>3</Version> </PandocSettings> </EBookSettings> <PostProcessing Enabled="Yes" Type="Script"> <Shell>/usr/bin/env ruby</Shell> <Script><![CDATA[#!/usr/bin/env ruby # encoding: utf-8 # scrivomatic is a wrapper script that adds tools to the path (as Scrivener # does not use the user's path), and enables some other tweaks to optimise # the workflow when Scrivener calls Pandocomatic. # `scrivomatic --help` for details… Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 require 'open3' # ruby standard library class to handle stderr and stdout require 'optparse' # ruby standard option parser require 'fileutils' # ruby standard library to deal with files require 'shellwords' # escapes strings to run in the shell #require 'debug/open_nonstop' # debugger, use binding.break to stop ## # main scrivomatic class class Scrivomatic ## # Sets up the path and performs other functions to improve running # pandocomatic from scrivener... attr_accessor :options attr_reader :version, :cmd, :runLog VER = '1.0.42'.freeze OPT = Struct.new(:input, :output, :to, :yaml, :command, :envpath, :build, :cleanup, :verbose, :dry_run, :open_log, :data_dir) DEFENVPATH = ENV['HOME'] + '/bin' #-------------------------------class constructor def initialize @options = OPT.new(nil, nil, nil, nil, 'pandocomatic', DEFENVPATH, false, false, false, false, false, nil) @version = VER @fileext = '' @cmd = '' @toolPath = '' @runLog = '' @latexEngine = 'xelatex' end #-------------------------------run all options def run preBuild # removes old tex file if user passed -b makePath # build the path to find our tools printInfo # print some information buildCommand # build the pandocomatic command runCommand # run the pandocomatic command postBuildTeX # run latexmk if user passed -b postBuildTypst # run typst if user passed -b end #--------------------------------checks if a file is less than 1.5 minutes old def isRecent(infile) File.exist?(infile) && (Time.now - File.mtime(infile)) <= 90 end #--------------------------------if we will run latexmk, remove old tex file before running pandoc def preBuild return unless options.build && !(options.dry_run) texPath = options.input.gsub(/#{@fileext}$/, '.tex') texFile = texPath.gsub(/\\+/, '') if File.exist?(texFile) puts "\n===------ Delete OLD TeX File: #{texFile}: ------===" if @options[:verbose] == true system("latexmk -quiet -c #{texFile} >/dev/null 2>&1") File.delete(texFile) end end #-------------------------------make env path def makePath home = ENV['HOME'] + '/' pathtest = [home+'.pixi/bin', home+'.rbenv/shims', home+'.pyenv/shims', '/opt/homebrew/opt/ruby/bin', '/opt/homebrew/lib/ruby/gems/3.4.0/bin', # note homebrew installs ruby as keg only! '/usr/local/opt/ruby/bin', '/usr/local/lib/ruby/gems/3.4.0/bin', home+'bin', '/opt/homebrew/bin', '/usr/local/bin', home+'Library/TinyTeX/bin/universal-darwin', '/Library/TeX/texbin', home+'anaconda/bin', home+'anaconda3/bin', home+'miniconda/bin', home+'miniconda3/bin', home+'micromamba/bin', home+'.cabal/bin', home+'.local/bin'] pathtest.each { |p| @options[:envpath] = @options[:envpath] + ':' + p if File.directory?(p) } ENV['LANG'] = 'en_GB.UTF-8' if ENV['LANG'].nil? # Just in case we have no LANG, which breaks UTF8 encoding @options[:envpath].gsub!(%r{(//)}, '/') # remove double slash @options[:envpath].gsub!(/(::)/, ':') # remove double colon @options[:envpath].gsub!(/:$/, '') # remove final colon ENV['PATH'] = @options[:envpath] + ':' + ENV['PATH'] end # end makePath() #-------------------------------print initial report def printInfo return if @options[:verbose] == false puts "\n=== ------------------------------------------------------ ===" puts '=== Scrivomatic V' + @version + ' Report @ ' + Time.now.to_s + ' ===' puts '=== ------------------------------------------------------ ===' puts ' Running shell: ' + `printf $SHELL` puts ' Working directory: ' + `pwd` puts " Initiating with Ruby #{RUBY_VERSION}" puts '===------ Input Options: ------===' puts @options puts '===------ Final ENV PATH: ------===' puts ENV['PATH'] puts '===------ TOOL PATHS: ------===' puts `echo "---pandoc: $(which pandoc) | V: $(pandoc -v | sed -nE '1 s/^pandoc // gp')"` puts `echo "---ruby: $(which ruby) | V: $(ruby -v)"` puts '!--ruby version incompatible with new pandocomatic, see https://github.com/iandol/scrivomatic/blob/master/Installing-Ruby.md' if `ruby -v` =~ /ruby 2\.3\.\d/ puts `echo "---pandocomatic: $(which pandocomatic) | V: $(pandocomatic -v | sed -En '1s/^Pandocomatic version /''/p')"` puts '---paru library: V: ' + `ruby -e 'require "paru"; puts Paru::VERSION.join(".")'` puts `echo "---rbenv versions:"; [[ -x $(which rbenv) ]] && rbenv versions` %w[pixi rbenv rvm gem python xelatex latexmk].each do |c| location = `which #{c}`.chomp puts "---#{c}: #{location}" unless location.empty? end puts "\n … running #{@options[:command]}, please wait …\n" end #-------------------------------build the command line def buildCommand @cmd += ' --data-dir="' + @options[:data_dir] + '"' unless @options[:data_dir].nil? @cmd += ' --output ' + @options[:output] + ' ' unless @options[:output].nil? @cmd += ' --to "' + @options[:to] + '"' unless @options[:to].nil? @cmd += ' -c ' + @options[:yaml] if !@options[:yaml].nil? && @options[:command] == 'pandocomatic' @cmd += ' --enable pandoc-verbose --log pandocomatic.log --log-level debug' if @options[:verbose] == true && @options[:command] == 'pandocomatic' @toolPath = `which #{@options[:command]}`.chomp @cmd = @toolPath + @cmd + ' ' + @options[:input] + ' ' unless @options[:input].nil? end #-------------------------------run the command def runCommand puts '===------ COMMAND OUTPUT: ------===' if @options[:verbose] == true if File.exist?(@toolPath) && !options.dry_run puts ":: Running: #{@cmd}\n" if @options[:verbose] == true Open3.popen2e(@cmd) do |_stdin, oe, thread| while (line = oe.gets) puts '::: ' + line.chomp if @options[:verbose] == true check_engine = line.match(/pdf-engine=(\w+)/) @latexEngine = check_engine[1] unless check_engine.nil? end exit_status = thread.value puts ':: pandocomatic exit status: ' + exit_status.to_s if @options[:verbose] == true unless exit_status.success? puts "\n!!!---scrivomatic::runCommand() RETURN non-zero value: #{cmd}!!!" end end `open scrivomatic.log` if @options[:open_log] && isRecent('scrivomatic.log') `open pandocomatic.log` if @options[:open_log] && isRecent('pandocomatic.log') elsif !options.dry_run puts "Tool doesn't exist!!!" if @options[:verbose] == true puts "\n!!!---scrivomatic::runCommand() Couldn't find #{@toolPath} to run, please supply a proper path!" elsif @options[:verbose] == true puts 'Dry run, nothing actually executed...' end end #-------------------------------parse inputs def parseInputs(_arg) optparse = OptionParser.new do |opts| opts.banner = 'Scrivomatic V' + @version + "\n" opts.banner += "=======================\n" opts.banner += "Scrivomatic is a wrapper to set up the shell environment, enforces UTF8 encoding and other settings.\n\n" opts.banner += 'Usage: scrivomatic [additional options] FILE' opts.on('-i', '--input FILE', 'Input file') do |v| v.gsub!(/(\A'|'\Z)/, '') @options[:input] = v.shellescape @fileext = Regexp.escape(File.extname(@options[:input])) end opts.on('-o', '--output [file]', 'Output file. Optional for pandocomatic.') do |v| @options[:output] = v.shellescape end opts.on('-t', '--to [format]', 'Pandoc Format. Optional for pandocomatic.') do |v| @options[:to] = v end opts.on('-y', '--yaml [file]', 'Specify which YAML file for pandocomatic.') do |v| @options[:yaml] = v.strip.shellescape end opts.on('-p', '--path [dirpath]', 'Additional Path to Search for Commands.') do |v| @options[:envpath] = v.strip.shellescape + ':' + @options[:envpath] end opts.on('-b', '--build', 'For Typst or LaTeX, run Typst and latexmk') do |v| @options[:build] = v end opts.on('-B', '--buildclean', 'For LaTeX or Typst, run Typst and latexmk with cleanup') do |v| @options[:build] = v @options[:cleanup] = v end opts.on('-d', '--dry-run', 'Dry run.') do |v| @options[:dry_run] = v end opts.on('-z', '--data-dir [file]', 'Pandoc data dir.') do |v| @options[:data_dir] = v.strip.shellescape end opts.on('-v', '--[no-]verbose', 'Verbose output.') do |v| @options[:verbose] = v end opts.on('-l', '--[no-]log', 'View log in Console.app.') do |v| @options[:open_log] = v end opts.on('-h', '--help', 'Prints this help!') do puts optparse exit(0) end end # end OptionParser optparse.parse! # make sure we have an input file return unless @options[:input].nil? # otherwise check if we got passed the file if ARGV.nil? || ARGV[0].nil? puts optparse abort "\n\n!!!---scrivomatic::parseInputs requires valid input file: --input" else v = ARGV[0].gsub(/(\A'|'\Z)/, '') # scrivener sometimes passes the file wrapped in ' @options[:input] = v.shellescape # we assume it was passed without -i flag @fileext = Regexp.escape(File.extname(@options[:input])) end end # end parseInputs #------------------------------check if we want to run latexmk def postBuildTeX return unless options.build && !(options.dry_run) texPath = options.input.gsub(/#{@fileext}$/, '.tex') texFile = texPath.gsub(/\\+/, '') pdfFile = texPath.gsub(/\.tex/, '.pdf') if isRecent(texFile) if File.exist?(pdfFile) puts "\n===------ Remove old #{pdfFile} ------===" if @options[:verbose] == true File.delete(pdfFile) end puts "\n===------ RUN LATEXMK on #{texPath}: ------===" if @options[:verbose] == true @latexEngine = 'pdf' if @latexEngine =~ /pdflatex/ xcmd = "latexmk -logfilewarnings -interaction=nonstopmode -f -pv -time -#{@latexEngine} -f #{texPath}" puts ":: directory: #{Dir.pwd}" if @options[:verbose] == true puts ":: command: #{xcmd}" if @options[:verbose] == true begin Open3.popen2e(xcmd) do |_stdin, oe, wait_thr| while (line = oe.gets) if line.chomp.to_s =~ /^(Latexmk:|Run|LaTeX|This is|===|Accumulated|Missing|! )/ puts '::: ' + line.chomp if @options[:verbose] == true end end exit_status = wait_thr.value puts ':: exit status: ' + exit_status.to_s if @options[:verbose] == true if exit_status.success? && @options[:cleanup] == true logPath = File.basename(options.input, '.*') + '.log' FileUtils.cp(logPath, 'latexlog_' + logPath) if File.file?(logPath) `latexmk -C -quiet` puts ":: Clean-up: used latexmk -c, but kept the latex build log as #{'latexlog_' + logPath}" if @options[:verbose] == true elsif !exit_status.success? puts "!!!---Scrivomatic: errors on build #{xcmd}, check logs!!!" end end rescue StandardError => e puts e end else puts "===Scrivomatic postBuildTeX: did not find #{texPath}" end end # This method performs post-build actions for Typst files. # It checks if the build option is enabled and not in dry-run mode. # It converts the input file path to a Typst file path and checks if the Typst file is recent. # If the Typst file is recent, it removes any existing PDF file and runs the Typst compile command. # The method logs various actions and outputs if the verbose option is enabled. # If the Typst compile command is successful and the cleanup option is enabled, it logs success. # If the Typst compile command fails, it logs an error message. # If the Typst file is not found, it logs a message indicating the file was not found. def postBuildTypst return unless options.build && !options.dry_run typPath = options.input.gsub(/#{@fileext}$/, '.typst').gsub(/\\+/, '') pdfFile = typPath.gsub(/\.typst/, '.pdf') unless isRecent(typPath) puts "===Scrivomatic postBuildTypst: did not find #{typPath}" if @options[:verbose] return end if File.exist?(pdfFile) puts "\n===------ Remove old #{pdfFile} ------===" if @options[:verbose] File.delete(pdfFile) end puts "\n===------ RUN TYPST on #{typPath}: ------===" if @options[:verbose] xcmd = "typst compile --pdf-standard a-2b #{typPath}" puts ":: directory: #{Dir.pwd}" if @options[:verbose] puts ":: command: #{xcmd}" if @options[:verbose] begin Open3.popen2e(xcmd) do |_stdin, oe, wait_thr| while (line = oe.gets) puts '::: ' + line.chomp if @options[:verbose] end exit_status = wait_thr.value puts ':: exit status: ' + exit_status.to_s if @options[:verbose] if exit_status.success? puts ":: Success" if @options[:verbose] else puts "!!!---Scrivomatic: errors on build #{xcmd}, check logs!!!" end end rescue StandardError => e puts "Error during Typst compilation: #{e.message}" end end end #--------------- end Scrivomatic class ########################################## ##########################################RUN Code #binding.break scriv = Scrivomatic.new scriv.parseInputs(ARGV) scriv.run ]]></Script> <Path>/Users/ian/Desktop/workflow_mmd/scrivomatic.rb</Path> <Args>-l -v -b "&lt;$inputfile&gt;" &gt;&gt;scrivomatic.log 2&gt;&amp;1</Args> </PostProcessing> </CompileFormat>