1# docidx.tcl --
2#
3#	The docidx export plugin. Generation of docidx markup.
4#
5# Copyright (c) 2009 Andreas Kupries <andreas_kupries@sourceforge.net>
6#
7# See the file "license.terms" for information on usage and redistribution
8# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
9#
10# RCS: @(#) $Id: export_docidx.tcl,v 1.3 2009/08/07 18:53:11 andreas_kupries Exp $
11
12# This package is a plugin for the doctools::idx v2 system.  It takes
13# the list serialization of a keyword index and produces text in
14# docidx format.
15
16# ### ### ### ######### ######### #########
17## Requisites
18
19# @mdgen NODEP: doctools::idx::export::plugin
20
21package require Tcl 8.4
22package require doctools::idx::export::plugin ; # Presence of this
23						# pseudo package
24						# indicates execution
25						# inside of a properly
26						# initialized plugin
27						# interpreter.
28package require doctools::idx::structure      ; # Verification that
29						# the input is proper.
30
31# ### ### ### ######### ######### #########
32## API.
33
34proc export {serial configuration} {
35
36    # Phase I. Check that we got a canonical index serialization. That
37    #          makes the unpacking easier, as we can mix it with the
38    #          generation of the output, knowing that everything is
39    #          already sorted as it should be.
40
41    ::doctools::idx::structure verify-as-canonical $serial
42
43    # ### ### ### ######### ######### #########
44    # Configuration ...
45    # * Standard entries
46    #   - user   = person running the application doing the formatting
47    #   - format = name of this format
48    #   - file   = name of the file the index came from. Optional.
49    #   - map    = maps symbolic references to actual file path. Optional.
50    # * docidx specific entries
51    #   - newlines = boolean. tags separated by eol markers
52    #   - indented = boolean. tags indented per the index structure.
53    #   - aligned  = boolean. reference information tabular aligned within keys.
54    #
55    # Notes
56    # * This format ignores 'map' even if set, as the written docidx
57    #   contains the symbolic references and only them.
58    # * aligned  => newlines
59    # * indented => newlines
60
61    # Combinations of the format specific entries
62    # N I A |
63    # - - - + ---------------------
64    # 0 0 0 | Ultracompact (no whitespace, single line)
65    # 1 0 0 | Compact (no whitespace, multiple lines)
66    # 1 1 0 | Indented
67    # 1 0 1 | Tabular aligned references
68    # 1 1 1 | Indented + Tabular aligned references
69    # - - - + ---------------------
70    # 0 1 0 | Not possible, per the implications above.
71    # 0 0 1 | ditto
72    # 0 1 1 | ditto
73    # - - - + ---------------------
74
75    # Import the configuration and initialize the internal state
76    array set config {
77	newlines 0
78	aligned  0
79	indented 0
80    }
81    array set config $configuration
82    array set types {
83	manpage {manpage}
84	url     {url    }
85    }
86
87    # Force the implications mentioned in the notes above.
88    if {
89	$config(aligned) ||
90	$config(indented)
91    } {
92	set config(newlines) 1
93    }
94
95    # ### ### ### ######### ######### #########
96
97    # Phase II. Generate the output, taking the configuration into
98    #           account.
99
100    TagsBegin
101
102    # First some comments about the provenance of the output.
103    Tag+ comment [list "Generated @ [clock format [clock seconds]]"]
104    Tag+ comment [list "By          $config(user)"]
105    if {[info exists config(file)] && ($config(file) ne {})} {
106	Tag+ comment [list "From file   $config(file)"]
107    }
108
109    # Unpack the serialization.
110    array set idx $serial
111    array set idx $idx(doctools::idx)
112    unset     idx(doctools::idx)
113    array set r $idx(references)
114
115    # Now open the markup
116
117    Tag+ index_begin [list $idx(label) $idx(title)]
118
119    # Iterate over the keys and their references
120    foreach {keyword references} $idx(keywords) {
121	# Print the key
122	if {$config(indented)} {TagPrefix {    }}
123	Tag+ key [list $keyword]
124
125	# Print the references in the key
126	if {$config(aligned)} { Align $references max }
127	if {$config(indented)} {TagPrefix {        }}
128
129	# Iterate over the references
130	foreach id $references {
131	    foreach {type label} $r($id) break
132	    if {$config(aligned)} {
133		set id [FmtR max $id]
134		set type $types($type)
135	    } else {
136		set id [list $id]
137	    }
138	    Tag+ $type $id [list $label]
139	}
140    }
141
142    # Close the index
143    TagPrefix {}
144    Tag+ index_end
145
146    # Last formatting, joining the commands together.
147    set sep [expr {$config(newlines) ? "\n" : ""}]
148    return [join $lines $sep]
149
150    # ### ### ### ######### ######### #########
151}
152
153# ### ### ### ######### ######### #########
154
155proc TagPrefix {str} {
156    upvar 1 prefix prefix
157    set    prefix $str
158    return
159}
160
161proc TagsBegin {} {
162    upvar 1 prefix prefix lines lines
163    set prefix {}
164    set lines  {}
165    return
166}
167
168proc Tag {n args} {
169    upvar 1 prefix prefix
170    set    cmd $prefix
171    append cmd \[$n
172    if {[llength $args]} { append cmd " [join $args]" }
173    append  cmd \]
174    return $cmd
175}
176
177proc Tag+ {n args} {
178    upvar 1 prefix prefix lines lines
179    lappend lines [eval [linsert $args 0 Tag $n]]
180    return
181}
182
183proc Align {references mv} {
184    upvar 1 $mv max r r
185    # Generate a list of references sortable by name, and also find the
186    # max length of all relevant names.
187    set max 0
188    foreach id $references {
189	Max max [list $id]
190    }
191    return
192}
193
194proc Max {v str} {
195    upvar 1 $v max
196    set x [string length $str]
197    if {$x <= $max} return
198    set max $x
199    return
200}
201
202proc FmtR {v str} {
203    upvar 1 $v max
204    return [list $str][string repeat { } [expr {$max - [string length [list $str]]}]]
205}
206
207# ### ### ### ######### ######### #########
208## Ready
209package provide doctools::idx::export::docidx 0.1
210return
211