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