Longer post
Please allow me to share my findings with you. I've divided my answer into three parts: no traffic, one-way traffic and two-way traffic, each part resulting in its own compilable TeX file.
I have used Xindy because MakeIndex is rather limited for non-English languages. On the other hand, I am using rather old makeidx
package, but I would recommend to use the imakeidx
package because we could save one I/O write slot in the last part. I wanted to compare methods, I used that way.
I am using lualatex
to process the TeX files, but any major latex
engine can be used.
No transportation: remarks on the mal-expex-1.tex
file
As it was already pointed out on it, we can redefine \@wrindex
as it is the key part called by the \index
command. We can store the information directly by calling for \ep@rawexnoprint
, see line 19 in the first file. That's the command the expex
package uses to store information.
Next problem is how to notify the index processor about number dot number location. Xindy uses location class for this purpose, it uses several of them and we can create a new one. It can be done by define-location-class
plus we define accompanying markup-locref
for this new class, in addition to that we are adding parentheses. The last step would be to define the order of new location classes, with your permission, I will show you later how it can be done.
We run:
lualatex mal-expex-1.tex
xindy -M texindy -M expex-1 -L general -C utf8 mal-expex-1.idx
lualatex mal-expex-1.tex
The content of the mal-expex-1.idx
file is as follows:
\indexentry{Bratwurst}{2.1}
\indexentry{Sauerkraut}{2.2}
\indexentry{Striz}{2.3}
\indexentry{Oldman}{2.4}
\indexentry{Sauerkraut}{2.5}
I enclose the TeX code and a preview of three cropped pages. As we can see from the last page, this is the requested form, but Houston, we have a problem! Once we want clickable version of our document, the index cross-references are not working.
% run: *latex mal-expex-1.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex
\usepackage{filecontents}
\begin{filecontents*}{expex-1.xdy}
;; expex-1.xdy
(define-location-class "expexnumber" ("arabic-numbers" :sep "." "arabic-numbers"))
(markup-locref :open "(" :close ")" :class "expexnumber")
\end{filecontents*}
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
{\string\indexentry{#1}{\ep@rawexnoprint}}%
\endgroup
\@esphack#1%
}%End of \def\@wrindex...
\makeatother
\begin{document}
%\gathertags
\chapter{First chapter}
Some initial text.
\chapter{Second chapter}
The first approach.
\ex Bratwurst --- this example is followed by \index{Bratwurst} \xe
\ex Sauerkraut --- this example is followed by \index{Sauerkraut} \xe
\ex By \index{Striz} \xe
\ex By \index{Oldman} \xe
\ex Again \index{Sauerkraut} \xe
%\begingroup
%\def\thispagestyle#1{}%
\printindex
%\endgroup
\end{document}
One-way traffic: remarks on the mal-expex-2.tex
file
Well, I have already opened that Pandora's box, let me inform you how we can save our souls. That major problem brings me to load the hyperref
package and explore our further possibilities.
The idea was to use regular cross-references as we know it from \label
+\ref
+\pageref
combination, no matter of what will be typeset in the index location of index entries.
I have redefined the \@wrindex
, added |myhyperlink{\ep@rawexnoprint}
which helps us to control the output. The key step was adding \label{\ep@rawexnoprint}#1
into this command. It stores reference information and prints the reference for us, therefore we don't have to type it twice.
We notify the index processor about a new command by define-attributes
and we define a new class as in the first example. The result of our efforts is that the number is clickable, the parentheses are not.
There is a small problem as hyperref
is redefining commands that it is clickable but it leads us to the page not to the line where \index
command was called. If we explore the mal-expex-2.aux
file further we can see what's going on:
\newlabel{2.1}{{1}{2}{Second chapter}{chapter.2}{}}
It stored all the necessary information, but it leads to the second chapter. That's not the best result we can achieve here as the title itself could be typeset several pages earlier than the expex
examples. Well, we have got some improvement. We are getting error messages from xindy
about cross-reference-targets not existing, but we can ignore them, we manage that part by ourselves.
We run these three lines:
lualatex mal-expex-2.tex
xindy -M texindy -M expex-2 -L general -C utf8 mal-expex-2.idx
lualatex mal-expex-2.tex
The content of the mal-expex-2.idx
file is this:
\indexentry{Bratwurst|myhyperlink{2.1}}{2.1}
\indexentry{Sauerkraut|myhyperlink{2.2}}{2.2}
\indexentry{Striz|myhyperlink{2.3}}{2.3}
\indexentry{Oldman|myhyperlink{2.4}}{2.4}
\indexentry{Sauerkraut|myhyperlink{2.5}}{2.5}
I enclose the TeX code and a preview of the result.
% run: *latex mal-expex-2.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex
\usepackage[colorlinks]{hyperref}
\usepackage{filecontents}
\begin{filecontents*}{expex-2.xdy}
;; expex-2.xdy
(define-attributes (("default" "textbf" "textit" "myhyperlink")))
(define-crossref-class "myhyperlink")
(markup-crossref-list :class "myhyperlink" :sep ",\,")
(markup-crossref-layer :open "(\myhyperlink{" :close "})" :class "myhyperlink")
\end{filecontents*}
\def\myhyperlink#1{\hyperref[#1]{#1}}
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
{\string\indexentry{#1|myhyperlink{\ep@rawexnoprint}}{\ep@rawexnoprint}}%
\endgroup
\@esphack\label{\ep@rawexnoprint}#1}%
\makeatother%End of \def\@wrindex...
\begin{document}
%\gathertags
\chapter{First chapter}
Some initial text.
\chapter{Second chapter}
The first approach.
\ex Bratwurst --- this example is followed by \index{Bratwurst} \xe
\ex Sauerkraut --- this example is followed by \index{Sauerkraut} \xe
\ex By \index{Striz} \xe
\ex By \index{Oldman} \xe
\ex Again \index{Sauerkraut} \xe
%\begingroup
%\def\thispagestyle#1{}%
\printindex
%\endgroup
\end{document}
Two-way traffic: remarks on the mal-expex-3.tex
file
Once we can improve something, we will. We wish to have clickable version of the document with cross-references leading to the proper locations. Moreover, we can try to have cross-references from both directions. From \index
to the index and from index entries in index back to its \index
counterparts. We must bear in mind that index entries are grouped and we may lose some hyperlinks in index, generally speaking.
For this I used a couple of \hypertarget
and \hyperlink
commands assuring I provide them unique markers, see lines 40-47 in the code below. It is corrected version, it goes to the original location, but there is no way back. Let's focused on that feature.
I have prepared a new file for next experiments to separate them from regular idx
file for purpose of this post. I will use myi
extension (reflects the idx
file) and iym
extension (reflects the ind
file).
The core of this method is to use \hypertarget
and \hyperlink
twice: one pair handling one way, the other pair handling the way back. Please see lines 50-65 in the code. I needed to use \raisebox
to get location from left baseline of the box to the left top corner.
I also prepared a new set of commands for regular use. We can store page numbers (it is a common method; plain arabic number), we can store number of expex
example (arabic number dot arabic number wrapped in the parentheses) and chapter number (arabic number wrapped in the brackets). Using this approach, see lines 68-70, we can store almost anything there.
The only remaining thing we must do is to notify xindy
about all this. Let's extend our xdy
style file, please see lines 20-36 in the TeX code.
To make our work easier I have done one more improvement. I have redefined the \ex...\xe
statements to the form of just \ex...
by defining the end of the line (^^M
) as a command and using it afterwards. This step is of course not necessary in production, I just wanted to show you that it can be done and we can save typing of \xe
.
We run the following four lines:
lualatex mal-expex-3.tex
xindy -M texindy -M expex-3 -L general -C utf8 -o mal-expex-3.ind mal-expex-3.idx
xindy -M texindy -M expex-3 -L general -C utf8 -o mal-expex-3.iym mal-expex-3.myi
lualatex mal-expex-3.tex
The content of the mal-expex-3.idx
file is the same as in the second part, because we redefined commands at the TeX level. The content of the mal-expex-3.myi
file is something new for us and it looks like this:
\indexentry{on purpose|malchapter{2-2-1}}{2}
\indexentry{paja|malpage{2-2-2}}{2}
\indexentry{malipivo|malpage{2-2-3}}{2}
\indexentry{next a|malexpex{2.8-2-4}}{2}
\indexentry{more a|malexpex{2.9-2-5}}{2}
\indexentry{next b|malchapter{2-2-6}}{2}
\indexentry{more b|malchapter{2-2-7}}{2}
\indexentry{paja|malexpex{2.12-2-8}}{2}
\indexentry{paja|malchapter{2-2-9}}{2}
I enclose the last example and a preview of our efforts.
% run: *latex mal-expex-3.tex
\documentclass{report}
\pagestyle{empty}
\usepackage{expex}
\lingset{aboveexskip=0pt,glspace=1em plus .5em minus.2em,
glrightskip=0pt plus 8em,aboveglftskip=0pt,glneveryline={\it},
glstyle=nlevel,everygl={\hangindent=1.2em \hangafter=1},
exnotype=chapter.arabic}
\usepackage{makeidx}
\makeindex
\usepackage[colorlinks=true]{hyperref}
\usepackage{filecontents}
\begin{filecontents*}{expex-3.xdy}
;; expex-3.xdy
(define-location-class "expexnumber" ("arabic-numbers" :sep "." "arabic-numbers"))
(define-location-class "expexchapter" ("arabic-numbers" :sep "."))
(define-location-class-order ("expexnumber" "expexchapter" "arabic-numbers"))
(define-attributes (("malpage" "malexpex" "malchapter" "myhyperlink")))
(define-crossref-class "myhyperlink")
(markup-crossref-list :class "myhyperlink" :sep ",\,")
(markup-crossref-list :open "(\myhyperlink{" :close "})" :class "myhyperlink")
(define-crossref-class "malpage")
(markup-crossref-list :class "malpage" :sep ",\,")
(markup-crossref-layer :open "\myhyper{" :close "}" :class "malpage")
(define-crossref-class "malexpex")
(markup-crossref-list :class "malexpex" :sep ",\,")
(markup-crossref-layer :open "(\myhyper{" :close "})" :class "malexpex")
(define-crossref-class "malchapter")
(markup-crossref-list :class "malchapter" :sep ",\,")
(markup-crossref-layer :open "[\myhyper{" :close "}]" :class "malchapter")
\end{filecontents*}
% Redefinition in common index... (one-way approach)
\def\myhyperlink#1{\hyperlink{#1}{#1}}
\makeatletter
\def\@wrindex#1{%
\protected@write\@indexfile{}%
{\string\indexentry{#1|myhyperlink{\ep@rawexnoprint}}{\ep@rawexnoprint}}%
\endgroup
\@esphack\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{\ep@rawexnoprint}{\raisebox{-\baselineskip}[0pt][0pt]{#1}}}}%
\makeatother
% A new index file...
\makeatletter
\let\temphere=\ep@rawexnoprint
\makeatother
\newwrite\myindexfile
\immediate\openout\myindexfile=\jobname.myi
\def\myhyper#1{\myhypertemp #1 }
\def\myhypertemp #1-#2-#3 {\hyperlink{#3}{\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{#3-to-index}}#1}}
% Two-way approach...
\newcount\mycounter
\mycounter=0
\def\myshipping#1#2{%
\global\advance\mycounter by 1%
\raisebox{\baselineskip}[0pt][0pt]{\hypertarget{\the\mycounter}{}}%
\hyperlink{\the\mycounter-to-index}{#1}%
\immediate\write\myindexfile{\string\indexentry{#1|\material{#2-\thepage-\the\mycounter}}{\thepage}}%
}% End of \myshipping...
% Regular definitions to be used in document body...
\def\pageindex#1{\def\material{malpage}\myshipping{#1}{\thepage}}
\def\expexindex#1{\def\material{malexpex}\myshipping{#1}{\temphere}}
\def\chapterindex#1{\def\material{malchapter}\myshipping{#1}{\thechapter}}
\begin{document}
% The form of \ex...\xe rewritten to the form of \ex... only
% We are hacking the end of the line...
\catcode`\^^M=13
\def^^M{\par}
\let\extemp=\ex
\def\ex#1^^M{\extemp#1\xe}
%\gathertags
\chapter{First chapter}
Some initial text.
\chapter{Second chapter}
The first approach.
\ex Bratwurst --- this example is followed by \index{Bratwurst}
\ex Sauerkraut --- this example is followed by \index{Sauerkraut}
\ex By \index{Striz}
\ex By \index{Oldman}
\ex an experiment \chapterindex{on purpose}
\ex hello 1 \pageindex{paja}
\ex hello 2 \pageindex{malipivo}
\ex hello 3 \expexindex{next a}
\ex hello 4 \expexindex{more a}
\ex hello 5 \chapterindex{next b}
\ex hello 6 \chapterindex{more b}
\ex hello 7 \expexindex{paja}
\ex hello 8 \chapterindex{paja}
\ex finish \index{Sleep}
% A common index...
%\begingroup % Redefinition of \indexname...
%\def\thispagestyle#1{}%
\def\indexname{Common index\\ with example numbers\\(one-way traffic)}
\printindex
% An improved version of index...
\def\indexname{Index of\\ page, (exercise), [chapter]\\(two-way traffic)}
\immediate\closeout\myindexfile
\IfFileExists{\jobname.iym}{\input \jobname.iym}{}%
%\endgroup
\end{document}
Best Answer
This is a kind of proof of concept using ExPex and the
savepos
module of thezref
package. Thanks to David Carlisle for helping with thezref
code in chat.The basic idea is to set reference points of overlap and then pass those to the
textoffset
parameter of ExPex. This allows you to align multiple glossed examples with any previous one. The code defines one environment and 3 user macros:\begin{discourse} ... \end{discourse}
An environment to group examples in a discourse. This is a simple environment that simply resets the line number counter, but could be made more complex if you need to label each discourse and want to list them in a contents list, for example. For this I would use thetocloft
package.\spkr{}
this macro sets the line number and generates a speaker name.\overmk{}
this generates a label and keeps track of its position. The first example of a set (or in fact, the document, since labels are global) should contain an instance of this as its first element. Subsequent marks can be added anywhere in the gloss.\offset{}{}
this takes two labels (created by\overmk
) and sets an offset beginning at the second mark.A fourth macro
\deflargestlabel
is used in the preamble. It takes one obligatory argument for the longest anticipated speaker name, and one optional argument for the largest anticipated line number (default is 99).\deflargestlabel[<longest line number>]{<longest speaker name>}
Here's a full example. Note that the
zref
package is writing labels to the.aux
file, so you will need more than one compilation to make sure the references (and therefore the spacings) are correct.