Tuesday 15 October 2013

Zim hacks part 1: compile a manuscript

The following script runs in the Linux terminal and will compile a manuscript that has been divided into Chapters and Scenes in Zim Desktop Wiki. It's twitchy and a little annoying, but it's the first step in my attempts to find a comfortable Linux equivalent to Scrivener and yWriter. Scrivener runs natively if you don't mind some UI problems with dark-on-light OS themes and yWriter (sort of) runs in Wine, but I really want something that doesn't have all those qualifications added after the word 'runs'.


Zim works, but it doesn't have 'split into scenes' and 'compile into a single document' options like dedicated novel-writing software. BUT... it does have a simple directory structure that makes sense outside the program. It also has everything stored in plain text files. So, hacks :).

Note - one day I'll attempt to replicate these functions in Python so they can actually become Zim plugins.

The script - compile_manuscript.sh


#!/bin/bash
#compile_manuscript.sh: cats the files in targetdir and Chapter subdirectories
#$1: attachment directory %d

chapternum='1'
scenenum='1' #start the loop
maxnumscenes='0'
cd "$1" #into the attachment directory to count

#get the number of chapters
maxnumchaps=`ls -1 | grep -i .*.txt | wc -l`

#...then go back to the directory above $1 again
cd ..

#Print the contents of all files called Chapter_*.txt
while [ $chapternum -le $maxnumchaps ] ; do
 #add the chapter to the compiled file - first chapter overwrites
 if [ $chapternum -eq '1' ] ; then
  echo -e "CHAPTER" > "$1"".txt"
 else
  echo -e "CHAPTER" >> "$1"".txt"
 fi
 cat "$1""/Chapter_"$chapternum".txt" >> "$1"".txt"
 echo -e "END" >> "$1"".txt"

 #find the number of scenes for this chapter
 cd "$1"'/Chapter_'$chapternum
 scenenum='1'
 maxnumscenes=`ls -1 | grep -i .*.txt | wc -l`
 #back to the top-level directory
 cd ..
 cd ..
 #now add all the scenes for that chapter
 while [ $scenenum -le $maxnumscenes ] ; do

  echo -e "* * *" >> "$1"".txt"
  cat "$1""/Chapter_"$chapternum"/Scene_"$scenenum".txt" >> "$1"".txt"

  #remove trailing blank lines added by cat
  sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' "$1"".txt" > "tmp" #works
  mv "tmp" "$1"".txt"

  scenenum=$(( $scenenum + 1 ))
 done

 #resume the 'chapter' loop, increment and add scene break 
 chapternum=$(( $chapternum + 1 ))
done

#tidy up the final output by removing the zim headers if they exist
zimheader1="Content-Type: text/x-zim-wiki"
zimheader2="Wiki-Format: zim 0.4"

grep -v "$zimheader1" "$1"".txt" > "tmp"
grep -v "$zimheader2" "tmp" > "$1"".txt"
rm "tmp"

#just in case the filename had spaces in it
find -wholename "$1"".txt" -type f | rename 's/ /_/g'

How to use


The script can be run as a Zim 'custom tool' (Tools --> Custom Tools) like this: [path to location of script]/compile_manuscript.sh %d. Name the tool 'Compile Manuscript' and put whatever you like for the description.

This is where it gets twitchy. Your manuscript must be arranged like this:

  • Your Book's name (this can be whatever you like)
    • Chapter 1
      • Scene 1
      • Scene 2
As the script stands, it can only deal with chapters and scenes with exactly these names. It would be pretty easy to change it to use whatever scene names exist, but Zim sorts the list of scenes by alphanumeric order, so naming them this way also has the benefit that your manuscript is going to be in order.

To run, right click on the 'Your Book's Name' page and select the tool from the menu.

Alternatively, using the Linux terminal emulator, navigate to the directory that contains 'Your Book's Name'. Then run the script from there like so:

[path to location of script]/compile_manuscript.sh "full path to 'Your Book's Name"

If I remember right, you really do need the double quotes around the argument. Single quotes or no quotes made things go weird.

1 comment: