1# -*- tcl -*-
2#
3# -- Engine to convert a doctools document into plain text.
4#
5# Copyright (c) 2003-2019 Andreas Kupries <andreas_kupries@sourceforge.net>
6
7# # ## ### ##### ######## #############
8## Load shared code and modify it to our needs.
9
10dt_source _common.tcl
11dt_source _text.tcl
12
13proc c_copyrightsymbol {} {return "(c)"}
14
15# # ## ### ##### ########
16## Special manpage contexts
17
18# example     = if present, context is for an example
19# exenv       = if present, reference to example variant of current context
20
21proc Example!  {} { CAttrSet example . }
22proc Example?  {} { CAttrHas example }
23
24proc NewExample {} {
25    return [ContextNew Example { VerbatimOn ; Example! ; Prefix! "| " }] ; # {}
26}
27
28proc Example {} {
29    if {![CAttrHas exenv]} {
30	ContextPush
31	set exenv [NewExample]
32	ContextPop
33	CAttrSet exenv $exenv
34	ContextCommit
35    }
36    return [CAttrGet exenv]
37}
38
39proc NewList {what} {
40    # List contexts
41    # Per list type several contexts are required.
42    #puts_stderr "LIST OUT [CAttrName] NewList $what"
43
44    switch -exact -- $what {
45	enumerated {NewOrderedList}
46	itemized   {NewUnorderedList}
47	arguments -
48	commands  -
49	options   -
50	tkoptions -
51	definitions {NewDefinitionList}
52    }
53
54    #puts_stderr "LIST INN [CAttrName]"
55    return
56}
57
58proc NewUnorderedList {} {
59    # Itemized list - unordered list - bullet
60    # 1. Base context provides indentation.
61    # 2. First paragraph in a list item.
62    # 3. All other paragraphs.
63    ContextPush
64
65    set base [ContextNew Itemized {
66	LC
67	MarginIn
68	set bullet [IBullet]
69    }] ; # {}
70
71    set first [ContextNew First {
72	List! bullet $bullet [BlankMargin]
73    }] ; ContextSet $base ; # {}
74
75    set next [ContextNew Next {
76	MarginIn
77    }] ; ContextSet $base ; # {}
78
79    OUL $first $next
80    ContextCommit
81
82    ContextPop
83    ContextSet $base
84    return
85}
86
87proc NewOrderedList {} {
88    # Ordered list - enumeration - enum
89    # 1. Base context provides indentation.
90    # 2. First paragraph in a list item.
91    # 3. All other paragraphs.
92    ContextPush
93
94    set base [ContextNew Enumerated {
95	LC
96	MarginIn
97	set bullet [EBullet]
98    }] ; # {}
99
100    set first [ContextNew First {
101	List! enum $bullet [BlankMargin]
102    }] ; ContextSet $base ; # {}
103
104    set next [ContextNew Next {
105	MarginIn
106    }] ; ContextSet $base ; # {}
107
108    OUL $first $next
109    ContextCommit
110
111    ContextPop
112    ContextSet $base
113    return
114}
115
116proc NewDefinitionList {} {
117    # Definition list - terms & definitions
118    # 1. Base context provides indentation.
119    # 2. Term context
120    # 3. Definition context
121    ContextPush
122
123    set base [ContextNew Definitions {
124	LC
125	MarginIn
126    }] ; # {}
127
128    set term [ContextNew Term {
129	VerbatimOn
130    }] ; ContextSet $base ; # {}
131
132    set def [ContextNew Def {
133	MarginIn
134    }] ; ContextSet $base ; # {}
135
136    TD $term $def
137    ContextCommit
138
139    ContextPop
140    ContextSet $base
141    return
142}
143
144# # ## ### ##### ########
145##
146
147proc LC {} {
148    # Clear inherited list type information from the current context
149    CAttrUnset _first
150    CAttrUnset _next
151    CAttrUnset _term
152    CAttrUnset _definition
153}
154
155proc OUL {f n} {
156    CAttrSet _first $f
157    CAttrSet _next  $n
158}
159
160proc TD {t d} {
161    CAttrSet _term       $t
162    CAttrSet _definition $d
163}
164
165proc IsPara   {} { CAttrHas _next }
166proc Paras    {} { global __pcount ; set  __pcount }
167proc PAdvance {} {
168    global __pcount ; incr __pcount 1
169    #puts_stderr "    ZZZ/ItemParas/Advance:$__pcount"
170}
171proc PReset   {} {
172    #puts_stderr "    ZZZ/ItemParas/Reset"
173    global __pcount ; set  __pcount 0 }
174
175global __pcount  ; set __pcount  0
176global __pcstack ; set __pcstack {}
177
178proc PSave {} {
179    global __pcount __pcstack
180    lappend __pcstack $__pcount
181    PReset
182}
183
184proc PRestore {} {
185    global __pcount __pcstack
186    set __pcount  [lindex $__pcstack end]
187    set __pcstack [lrange $__pcstack 0 end-1]
188    #puts_stderr "    ZZZ/ItemParas/Restore:$__pcount"
189    return
190}
191
192proc First    {} { CAttrGet _first }
193proc Other    {} { CAttrGet _next }
194proc Term     {} { CAttrGet _term }
195proc Def      {} { CAttrGet _definition }
196proc IsDef    {} { CAttrHas _definition }
197
198# # ## ### ##### ########
199##
200
201proc CloseCurrent {} {
202    if {[IsDef]} {
203	#puts_stderr "    ZZZ/CloseCurrent/Definitions"
204	# Currently in a definition list.
205	CloseParagraph [Def]
206    } elseif {[IsPara]} {
207	#puts_stderr "    ZZZ/CloseCurrent/UOL"
208	# Currently in an (un)ordered list.
209	#puts_stderr "    ZZZ/ItemParas/[Paras]"
210	if {![Paras]} {
211	    # No paragraphs yet, this is first in the item
212	    if {[CloseParagraph [First]]} PAdvance
213	} else {
214	    # More paragraphs in the item
215	    if {[CloseParagraph [Other]]} PAdvance
216	}
217    } else {
218	#puts_stderr "    ZZZ/CloseCurrent/Plain"
219	# Currently in a regular paragraph
220	CloseParagraph
221    }
222}
223
224proc GetCurrent {} {
225    if {[IsDef]} {
226	#puts_stderr "    ZZZ/GetCurrent/Definitions"
227	# Currently in a definition list.
228	return [Def]
229    } elseif {[IsPara]} {
230	#puts_stderr "    ZZZ/GetCurrent/UOL"
231	# Currently in an (un)ordered list.
232	#puts_stderr "    ZZZ/ItemParas/[Paras]"
233	if {![Paras]} {
234	    set res [First]
235	} else {
236	    set res [Other]
237	}
238	PAdvance
239	return $res
240    } else {
241	#puts_stderr "    ZZZ/GetCurrent/Plain"
242	# Currently in a regular paragraph
243	return {}
244    }
245}
246
247# # ## ### ##### ########
248##
249
250c_holdBuffers require
251
252rename fmt_initialize   BaseInitialize
253proc fmt_initialize {} {BaseInitialize ; TextInitialize ; return}
254
255proc fmt_postprocess {text} { text_postprocess $text }
256
257# # ## ### ##### ########
258## Implementations of the formatting commands.
259
260c_pass 1 fmt_plain_text {text} NOP
261c_pass 2 fmt_plain_text {text} { text_plain_text $text }
262
263c_pass 1 fmt_manpage_begin {title section version} NOP
264c_pass 2 fmt_manpage_begin {title section version} {
265    Off
266    set module      [dt_module]
267    set shortdesc   [c_get_module]
268    set description [c_get_title]
269
270    set     hdr [list]
271    lappend hdr "$title - $shortdesc"
272    lappend hdr [c_provenance]
273    lappend hdr "[string trimleft $title :]($section) $version $module \"$shortdesc\""
274    set     hdr [join $hdr \n]
275
276    Text $hdr
277    CloseParagraph [Verbatim]
278    Section NAME
279    Text "$title - $description"
280    CloseParagraph
281    return
282}
283
284c_pass 1 fmt_moddesc   {desc} {c_set_module $desc}
285c_pass 2 fmt_moddesc   {desc} NOP
286
287c_pass 1 fmt_titledesc {desc} {c_set_title $desc}
288c_pass 2 fmt_titledesc {desc} NOP
289
290c_pass 1 fmt_copyright {desc} {c_set_copyright $desc}
291c_pass 2 fmt_copyright {desc} NOP
292
293c_pass 1 fmt_manpage_end {} NOP
294c_pass 2 fmt_manpage_end {} {
295    set sa [c_xref_seealso]
296    set kw [c_xref_keywords]
297    set ca [c_xref_category]
298    set ct [c_get_copyright]
299
300    CloseParagraph
301    if {[llength $sa] > 0} {Section {SEE ALSO} ; Text [join [lsort $sa] ", "] ; CloseParagraph}
302    if {[llength $kw] > 0} {Section KEYWORDS   ; Text [join [lsort $kw] ", "] ; CloseParagraph}
303    if {$ca ne ""}         {Section CATEGORY   ; Text $ca                     ; CloseParagraph}
304    if {$ct != {}}         {Section COPYRIGHT  ; Text $ct ; CloseParagraph [Verbatim]}
305    return
306}
307
308c_pass 1 fmt_section     {name {id {}}} NOP
309c_pass 2 fmt_section     {name {id {}}} {CloseParagraph ; Section $name ; return}
310
311c_pass 1 fmt_subsection  {name {id {}}} NOP
312c_pass 2 fmt_subsection  {name {id {}}} {CloseParagraph ; Subsection $name ; return}
313
314c_pass 1 fmt_para {} NOP
315c_pass 2 fmt_para {} {
316    CloseCurrent
317    #puts_stderr "AAA/fmt_para/START"
318    return
319}
320
321# NL is an alias of PARA
322# See also fmt_example_begin
323c_pass 1 fmt_nl {} NOP
324c_pass 2 fmt_nl {} {CloseCurrent ; return }
325
326c_pass 2 fmt_require {pkg {version {}}} NOP
327c_pass 1 fmt_require {pkg {version {}}} {
328    set result "package require $pkg"
329    if {$version != {}} {append result " $version"}
330    c_hold require $result
331    return
332}
333
334c_pass 1 fmt_usage {cmd args} {c_hold synopsis "$cmd [join $args " "]"}
335c_pass 2 fmt_usage {cmd args} NOP
336
337c_pass 1 fmt_call  {cmd args} {c_hold synopsis "$cmd [join $args " "]"}
338c_pass 2 fmt_call  {cmd args} {fmt_lst_item "$cmd [join $args " "]"}
339
340
341c_pass 1 fmt_description {id} NOP
342c_pass 2 fmt_description {id} {
343    On
344    set syn [c_held synopsis]
345    set req [c_held require]
346
347    if {$syn != {} || $req != {}} {
348	Section SYNOPSIS
349	if {($req != {}) && ($syn != {})} {
350	    Text $req\n\n$syn
351	} else {
352	    if {$req != {}} {Text $req}
353	    if {$syn != {}} {Text $syn}
354	}
355	CloseParagraph [Verbatim]
356    }
357
358    Section DESCRIPTION
359    return
360}
361
362# # ## ### ##### ########
363##
364
365c_pass 1 fmt_list_begin {what {hint {}}} NOP
366c_pass 2 fmt_list_begin {what {hint {}}} {
367    CloseCurrent
368
369    #puts_stderr "AAA/fmt_list_begin/Setup $what"
370
371    ContextPush ;# push outer
372    NewList $what ;# base/controller of current/new/inner
373    Off
374    PSave
375
376    #puts_stderr "AAA/fmt_list_begin/Enter"
377    return
378}
379
380c_pass 1 fmt_list_end {} NOP
381c_pass 2 fmt_list_end {} {
382    CloseCurrent
383
384    #puts_stderr "AAA/fmt_list_end/Exit"
385
386    ContextPop ;# return to outer
387    PRestore
388
389    #puts_stderr "AAA/fmt_list_end/Done"
390    return
391}
392
393c_pass 1 fmt_lst_item {text} NOP
394c_pass 2 fmt_lst_item {text} {
395    if {[IsOff]} { On } else { CloseParagraph [Def] }
396
397    #puts_stderr "AAA/fmt_lst_item/(($text))"
398
399    Text $text
400    CloseParagraph [Term]
401
402    #puts_stderr "AAA/fmt_lst_item/Done"
403    return
404}
405
406c_pass 1 fmt_bullet {} NOP
407c_pass 2 fmt_bullet {} {
408    if {[IsOff]} { On } else { CloseCurrent }
409
410    #puts_stderr "AAA/fmt_bullet/START"
411    PReset
412    return
413}
414
415c_pass 1 fmt_enum {} NOP
416c_pass 2 fmt_enum {} {
417    if {[IsOff]} { On } else { CloseCurrent }
418
419    #puts_stderr "AAA/fmt_enum/START"
420    PReset
421    return
422}
423
424c_pass 1 fmt_cmd_def  {command} NOP
425c_pass 2 fmt_cmd_def  {command} {fmt_lst_item [fmt_cmd $command]}
426
427c_pass 1 fmt_arg_def {type name {mode {}}} NOP
428c_pass 2 fmt_arg_def {type name {mode {}}} {
429    set text "$type [fmt_arg $name]"
430    if {$mode != {}} {append text " ($mode)"}
431    fmt_lst_item $text
432    return
433}
434
435c_pass 1 fmt_opt_def {name {arg {}}} NOP
436c_pass 2 fmt_opt_def {name {arg {}}} {
437    set text [fmt_option $name]
438    if {$arg != {}} {append text " $arg"}
439    fmt_lst_item $text
440    return
441}
442
443c_pass 1 fmt_tkoption_def {name dbname dbclass} NOP
444c_pass 2 fmt_tkoption_def {name dbname dbclass} {
445    set    text ""
446    append text "Command-Line Switch:\t[fmt_option $name]\n"
447    append text "Database Name:\t[Strong $dbname]\n"
448    append text "Database Class:\t[Strong $dbclass]\n"
449    fmt_lst_item $text
450}
451
452# # ## ### ##### ########
453##
454
455c_pass 1 fmt_example_begin {} NOP
456c_pass 2 fmt_example_begin {} {
457    #puts_stderr "AAA/fmt_example_begin"
458
459    CloseCurrent
460
461    #puts_stderr "AAA/fmt_example_begin/Done"
462    return
463}
464
465c_pass 1 fmt_example_end {} NOP
466c_pass 2 fmt_example_end {} {
467    #puts_stderr "AAA/fmt_example_end"
468    #puts_stderr AAA/EIN=[string map [list \1 \\1 \t \\t { } \\s] <<[join [split [Text?] \n] >>\n<<]>>]
469
470    # Flush markup from preceding commands into the text buffer.
471    TextPlain ""
472
473    TextTrimLeadingSpace
474
475    # Look for and convert continuation lines protected from Tcl
476    # substitution into a regular continuation line.
477    set t [string map [list \\\\\n \\\n] [Text?]]
478    TextClear
479    Text $t
480
481    #puts_stderr AAA/EFT=[string map [list \1\\1 \t \\t { } \\s] <<[join [split [Text?] \n] >>\n<<]>>]
482
483    set penv [GetCurrent]
484    if {$penv != {}} {
485	# In a list we save the current list context, activate the
486	# proper paragraph context and create its example
487	# variant. After closing the paragraph using the example we
488	# restore and reactivate the list context.
489	ContextPush
490	ContextSet $penv
491	#if {[CloseParagraph [Example]]} PAdvance
492	CloseParagraph [Example]
493	ContextPop
494    } else {
495	# In a regular paragraph we simple close the example
496	#if {[CloseParagraph [Example]]} PAdvance
497	CloseParagraph [Example]
498    }
499
500    #puts_stderr "AAA/fmt_example_end/Done"
501    return
502}
503
504c_pass 1 fmt_example {code} NOP
505c_pass 2 fmt_example {code} {
506    fmt_example_begin
507    fmt_plain_text $code
508    fmt_example_end
509    return
510}
511
512# # ## ### ##### ########
513## Visual markup of words and phrases.
514
515proc fmt_arg     {text} { return $text }
516proc fmt_cmd     {text} { return $text }
517proc fmt_emph	 {text} { Em     $text }
518proc fmt_opt     {text} { return "?$text?" }
519proc fmt_comment {text} { return }
520proc fmt_sectref {text {label {}}} {
521    if {![string length $label]} {set label $text}
522    return "-> $text"
523}
524
525proc fmt_syscmd  {text} { Strong $text }
526proc fmt_method  {text} { return $text }
527proc fmt_option  {text} { return $text }
528proc fmt_widget  {text} { Strong $text }
529proc fmt_fun     {text} { Strong $text }
530proc fmt_type    {text} { Strong $text }
531proc fmt_package {text} { Strong $text }
532proc fmt_class   {text} { Strong $text }
533proc fmt_var     {text} { Strong $text }
534proc fmt_file    {text} { return "\"$text\"" }
535proc fmt_namespace     {text} { Strong $text }
536proc fmt_uri     {text {label {}}} {
537    if {$label == {}} {
538	# Without label we use the link directly as part of the text.
539	return "<URL:$text>"
540    } else {
541	return "[Em $label] <URL:$text>"
542    }
543}
544proc fmt_image {text {label {}}} {
545    # text = symbolic name of the image.
546
547    set img [dt_imgdata $text {txt}]
548    if {$img != {}} {
549	if {$label == {}} {
550	    return "IMAGE: $text"
551	} else {
552	    return "IMAGE: $text $label"
553	}
554    }
555
556    return $img
557}
558
559proc fmt_term    {text} { Em     $text }
560proc fmt_const   {text} { Strong $text }
561proc fmt_mdash {} { return " --- " }
562proc fmt_ndash {} { return " -- " }
563
564# # ## ### ##### ########
565return
566