#!/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 plasTeX.TeX import TeX from unidecode import unidecode import sys import re import locale import warnings # 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. ''' tex = TeX() tex.input(value) return locale.strxfrm(unidecode(tex.parse().textContent.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() type = data[0] i = 1 idx = index() 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): self.data = dict() self.keywords = dict() 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 'prefix' in self.keywords: for prefix in self.keywords['prefix']: self.prefix_patterns.append(re.compile(r"^(%s)(\b|\\)(\s*.*)$" % prefix)) def add(self, key, number, link): for pattern in self.prefix_patterns: match = pattern.match(key) if match: key = "%s (%s)" % (match.group(2) + match.group(3), match.group(1)) break # Only one match per key (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 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 '\\idxentry{{{0}}}{{{1}}}\n'.format(key, '\\\\'.join(map(self.refToStr, entry))) else: return '\\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