Engine for LaTeX songbooks http://www.patacrep.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

155 lines
5.4 KiB

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Generate indexes files for the Crep's chordbook compilation. This is
# a replacement for the original makeindex program written in C that
# produces an index file (.sbx) from a file generated by the latex
# compilation of the songbook (.sxd).
#
# Usage : songbook-makeindex.py src
# src is the .sxd file generated by latex
#
from unidecode import unidecode
import sys
import re
import locale
import warnings
from tools import processauthors
from utils.plastex import simpleparse
# Pattern set to ignore latex command in title prefix
keywordPattern = re.compile(r"^%(\w+)\s?(.*)$")
firstLetterPattern = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)")
def sortkey(value):
'''
From a title, return something usable for sorting. It handles locale (but
don't forget to call locale.setlocale(locale.LC_ALL, '')). It also handles
the sort with latex escape sequences.
'''
return locale.strxfrm(unidecode(simpleparse(value).replace(' ', 'A')))
def processSXDEntry(tab):
return (tab[0], tab[1], tab[2])
def processSXD(filename):
file = open(filename)
data = []
for line in file:
data.append(line.strip())
file.close()
i = 1
idx = index(data[0])
if len(data) > 1:
while data[i].startswith('%'):
keywords = keywordPattern.match(data[i]).groups()
idx.keyword(keywords[0],keywords[1])
i += 1
idx.compileKeywords()
for i in range(i,len(data),3):
entry = processSXDEntry(data[i:i+3])
idx.add(entry[0],entry[1],entry[2])
return idx
class index:
def __init__(self, indextype):
self.data = dict()
self.keywords = dict()
if indextype == "TITLE INDEX DATA FILE":
self.indextype = "TITLE"
elif indextype == "SCRIPTURE INDEX DATA FILE":
self.indextype = "SCRIPTURE"
elif indextype == "AUTHOR INDEX DATA FILE":
self.indextype = "AUTHOR"
else:
self.indextype = ""
def filter(self, key):
letter = firstLetterPattern.match(key).group(1)
if re.match('\d',letter):
letter = '0-9'
return (letter.upper(), key)
def keyword(self, key, word):
if not self.keywords.has_key(key):
self.keywords[key] = []
self.keywords[key].append(word)
def compileKeywords(self):
self.prefix_patterns = []
if self.indextype == "TITLE":
if 'prefix' in self.keywords:
for prefix in self.keywords['prefix']:
self.prefix_patterns.append(re.compile(r"^(%s)(\b|\\)(\s*.*)$" % prefix))
self.authwords = {"after": [], "ignore": [], "sep": []}
if self.indextype == "AUTHOR":
for key in self.keywords:
if key in self.authwords:
self.authwords[key] = self.keywords[key]
for word in self.authwords.keys():
if word in self.keywords:
if word == "after":
self.authwords[word] = [re.compile(r"^.*%s\b(.*)" % after) for after in self.keywords[word]]
elif word == "sep":
self.authwords[word] = [" %s" % sep for sep in self.authwords[word]] + [","]
self.authwords[word] = [re.compile(r"^(.*)%s (.*)$" % sep) for sep in self.authwords[word] ]
else:
self.authwords[word] = self.keywords[word]
def _raw_add(self, key, number, link):
(first, key) = self.filter(key)
if not self.data.has_key(first):
self.data[first] = dict()
if not self.data[first].has_key(key):
self.data[first][key] = []
self.data[first][key].append({'num':number, 'link':link})
def add(self, key, number, link):
if self.indextype == "TITLE":
# Removing prefixes before titles
for pattern in self.prefix_patterns:
match = pattern.match(key)
if match:
self._raw_add(
"%s (%s)" % (match.group(2) + match.group(3), match.group(1)),
number, link)
return
self._raw_add(key, number, link)
if self.indextype == "AUTHOR":
# Processing authors
for author in processauthors(
key,
**self.authwords):
self._raw_add(author, number, link)
def refToStr(self, ref):
if sys.version_info >= (2,6):
return '\\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref)
else:
return '\\hyperlink{%(link)s}{%(num)s}' % ref
def entryToStr(self, key, entry):
if sys.version_info >= (2,6):
return unicode('\\idxentry{{{0}}}{{{1}}}\n').format(key, '\\\\'.join(map(self.refToStr, entry)))
else:
return unicode('\\idxentry{%s}{%s}\n') % (key, '\\\\'.join(map(self.refToStr, entry)))
def idxBlockToStr(self, letter, entries):
str = '\\begin{idxblock}{'+letter+'}'+'\n'
for key in sorted(entries.keys(), key=sortkey):
str += self.entryToStr(key, entries[key])
str += '\\end{idxblock}'+'\n'
return str
def entriesToStr(self):
str = ""
for letter in sorted(self.data.keys()):
str += self.idxBlockToStr(letter, self.data[letter])
return str