cmdr
Check-in [7104561dd4]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Pulled some stackato-cli utility packages into cmdr, incomplete work (tty, color, simple interaction)
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7104561dd4b259535d63c531966d87f9a2d19be3
User & Date: andreask 2014-05-23 00:30:03.010
References
2014-05-23
22:19 Closed ticket [a80ac87036]: Add facilities for user interaction plus 4 other changes artifact: 7ab7393038 user: aku
22:17 Ticket [8502a858bd] Add facility for colorization status still Closed with 3 other changes artifact: 2239702142 user: aku
22:17 Closed ticket [8502a858bd]. artifact: 26dcf622de user: aku
Context
2014-05-23
06:17
cmdr::actor - Better error message for "set" check-in: abd6c63e65 user: aku tags: trunk
00:30
Pulled some stackato-cli utility packages into cmdr, incomplete work (tty, color, simple interaction) check-in: 7104561dd4 user: andreask tags: trunk
2014-05-21
06:44
cmdr::parameter - Fix use of wrong variable in ValueRelease, use argument, not instance variable. check-in: 623a3ff06b user: aku tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Added ask.tcl.
































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## CMDR - Convenience commands for terminal-based user interaction.

# @@ Meta Begin
# Package cmdr::ask 0
# Meta author   {Andreas Kupries}
# Meta location https://core.tcl.tk/akupries/cmdr
# Meta platform tcl
# Meta summary     Terminal-based user interaction commands.
# Meta description Commands to interact with the user in various
# Meta description simple ways, for a terminal.
# Meta subject {command line} tty interaction terminal
# Meta require {Tcl 8.5-}
# Meta require debug
# Meta require debug::caller
# Meta require cmdr::color
# Meta require try
# Meta require linenoise
# Meta require struct::matrix
# Meta require textutil::adjust
# @@ Meta End

# # ## ### ##### ######## ############# #####################
## Requisites

package require Tcl 8.5
#package require cmdr::color
package require debug
package require debug::caller
package require linenoise
package require try
package require struct::matrix
package require textutil::adjust

namespace eval ::cmdr {
    namespace export ask
}
namespace eval ::cmdr::ask {
    #namespace import ::stackato::color
    namespace export string string/extended string* yn choose menu
    namespace create ensemble
}

# # ## ### ##### ######## ############# #####################

debug define cmdr/ask
debug level  cmdr/ask
debug prefix cmdr/ask {[debug caller] | }

# # ## ### ##### ######## ############# #####################

proc ::cmdr::ask::string {query {default {}}} {
    debug.cmdr/ask {}
    try {
	set response [Interact {*}[Fit $query 10]]
    } on error {e o} {
	if {$e eq "aborted"} {
	    error Interrupted error SIGTERM
	}
	return {*}${o} $e
    }
    if {($response eq {}) && ($default ne {})} {
	set response $default
    }
    return $response
}

proc ::cmdr::ask::string/extended {query args} {
    debug.cmdr/ask {}
    # accept  -history, -hidden, -complete
    # plus    -default
    # but not -prompt

    # for history ... integrate history load/save from file here?
    # -history is then not boolean, but path to history file.

    set default {}
    set config {}
    foreach {o v} $args {
	switch -exact -- $o {
	    -history -
	    -hidden -
	    -complete {
		lappend config $o $v
	    }
	    -default {
		set default $v
	    }
	    default {
		return -code error "Bad option \"$o\", expected one of -history, -hidden, -prompt, or -default"
	    }
	}
    }
    try {
	set response [Interact {*}[Fit $query 10] {*}$config]
    } on error {e o} {
	if {$e eq "aborted"} {
	    error Interrupted error SIGTERM
	}
	return {*}${o} $e
    }
    if {($response eq {}) && ($default ne {})} {
	set response $default
    }
    return $response
}

proc ::cmdr::ask::string* {query} {
    debug.cmdr/ask {}
    try {
	set response [Interact {*}[Fit $query 10] -hidden 1]
    } on error {e o} {
	if {$e eq "aborted"} {
	    error Interrupted error SIGTERM
	}
	return {*}${o} $e
    }
    return $response
}

proc ::cmdr::ask::yn {query {default yes}} {
    debug.cmdr/ask {}
    set dinfo [expr {$default
		     ? " \[Yn\]: "
		     : " \[yN\]: "}]
    # Reactivate with color support.
    if 0 {set dinfo [expr {$default
			   ? " \[[color green Y]n\]: "
			   : " \[y[color green N]\]: "}]}
    append query $dinfo

    lassign [Fit $query 5] header prompt
    while {1} {
	try {
	    set response \
		[Interact $header $prompt \
		     -complete [namespace code {Complete {yes no false true on off 0 1} 1}]]
		     
	} on error {e o} {
	    if {$e eq "aborted"} {
		error Interrupted error SIGTERM
	    }
	    return {*}${o} $e
	}
	if {$response eq {}} { set response $default }
	if {[string is bool $response]} break
	puts stdout [Wrap "You must choose \"yes\" or \"no\""]
    }

    return $response
}

proc ::cmdr::ask::choose {query choices {default {}}} {
    debug.cmdr/ask {}

    set hasdefault [expr {$default in $choices}]

    set lc [linsert [join $choices {, }] end-1 or]
    if {$hasdefault} {
	# when we have color support, reactivate
	#lappend map $default [color green $default]
	#set lc [string map $map $lc]
    }

    append query " ($lc): "

    lassign [Fit $query 5] header prompt

    while {1} {
	try {
	    set response \
		[Interact $header $prompt \
		     -complete [namespace code [list Complete $choices 0]]]
	} on error {e o} {
	    if {$e eq "aborted"} {
		error Interrupted error SIGTERM
	    }
	    return {*}${o} $e
	}
	if {($response eq {}) && $hasdefault} {
	    set response $default
	}
	if {$response in $choices} break
	puts stdout [Wrap "You must choose one of $lc"]
    }

    return $response
}

proc ::cmdr::ask::menu {header prompt choices {default {}}} {
    debug.cmdr/ask {}

    set hasdefault [expr {$default in $choices}]

    # Full list of choices is the choices themselves, plus the numeric
    # indices we can address them by. This is for the prompt
    # completion callback below.
    set fullchoices $choices

    # Build table (2-column matrix)
    struct::matrix [self namespace]::M
    M add columns 2
    set n 1
    foreach c $choices {
	if 0 {if {$default eq $c} {
	    M add row [list ${n}. [color green $c]]
	} else {
	    M add row [list ${n}. $c]
	}}

	M add row [list ${n}. $c]
	lappend fullchoices $n
	incr n
    }
    set Mstr [M format 2string]
    M destroy

    # Format the prompt
    lassign [Fit $prompt 5] pheader prompt

    # Interaction loop
    while {1} {
	if {$header ne {}} {puts stdout $header}
	puts stdout $Mstr

	try {
	    set response \
		[Interact $pheader $prompt \
		     -complete [namespace code [list Complete $fullchoices 0]]]
	} on error {e o} {
	    if {$e eq "aborted"} {
		error Interrupted error SIGTERM
	    }
	    return {*}${o} $e
	}
	if {($response eq {}) && $hasdefault} {
	    set response $default
	}

	if {$response in $choices} break

	if {[string is int $response]} {
	    # Inserting a dummy to handle indexing from 1...
	    set response [lindex [linsert $choices 0 {}] $response]
	    if {$response in $choices} break
	}

	puts stdout [Wrap "You must choose one of the above"]
    }

    return $response
}

# # ## ### ##### ######## ############# #####################

proc ::cmdr::ask::Complete {choices nocase buffer} {
    debug.cmdr/ask {}

    if {$buffer eq {}} {
	return $choices
    }

    if {$nocase} {
	set buffer [string tolower $buffer]
    }

    set candidates {}
    foreach c $choices {
	if {![string match ${buffer}* $c]} continue
	lappend candidates $c
    }
    return $candidates
}

proc ::cmdr::ask::Interact {header prompt args} {
    debug.cmdr/ask {}
    if {$header ne {}} { puts $header }
    return [linenoise prompt {*}$args -prompt $prompt]
}

proc ::cmdr::ask::Wrap {text {down 0}} {
    debug.cmdr/ask {}
    global env
    if {[info exists env(CMDR_NO_WRAP)]} {
	return $text
    }
    set c [expr {[linenoise columns]-$down}]
    return [textutil::adjust::adjust $text -length $c -strictlength 1]
}

proc ::cmdr::ask::Fit {prompt space} {
    debug.cmdr/ask {}
    # Similar to Wrap, except with a split following.
    global env
    if {[info exists env(CMDR_NO_WRAP)]} {
	return [list {} $prompt]
    }

    set w [expr {[linenoise columns] - $space }]
    # we leave space for some characters to be entered.

    if {[string length $prompt] < $w} {
	return [list {} $prompt]
    }

    set prompt [textutil::adjust::adjust $prompt -length $w -strictlength 1]
    set prompt [split $prompt \n]
    set header [join [lrange $prompt 0 end-1] \n]
    set prompt [lindex $prompt end]
    # alt code for the same.
    #set header [join [lreverse [lassign [lreverse [split $prompt \n]] prompt]] \n]
    append prompt { }

    return [list $header $prompt]
}

# # ## ### ##### ######## ############# #####################
## Ready
package provide cmdr::ask 0
Added color.tcl.






























































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## CMDR - Convenience commands for colored text in terminals.

# @@ Meta Begin
# Package cmdr::color 0
# Meta author   {Andreas Kupries}
# Meta location https://core.tcl.tk/akupries/cmdr
# Meta platform tcl
# Meta summary     Text colorization for terminal output
# Meta description Commands to manage colored text in terminal
# Meta description output
# Meta subject {command line} terminal color {text colors}
# Meta require {Tcl 8.5-}
# Meta require debug
# Meta require debug::caller
# Meta require cmdr::tty
# @@ Meta End

# # ## ### ##### ######## ############# #####################
## Requisites

package require Tcl 8.5
package require debug
package require debug::caller
package require cmdr::tty

# # ## ### ##### ######## ############# #####################

namespace eval ::cmdr::color {
    namespace export activate active define
    namespace ensemble create \
	-unknown [namespace current]::Unknown
    # Note, the option ensures that all unknown methods are treated as
    # (list of) color codes to apply to some text, effectively
    # creating the virtual command
    #
    #    ::cmdr::color <codelist> <text>
    ##

    namespace import ::cmdr::tty
}

# # ## ### ##### ######## ############# #####################

debug define cmdr/color
debug level  cmdr/color
debug prefix cmdr/color {[debug caller] | }

# # ## ### ##### ######## ############# #####################
## TODO undef?
## TODO multi-def (load)
## TODO get (display)
## officer and private for std commands (show, define).

proc ::cmdr::color::activate {{flag 1}} {
    debug.cmdr/color {}
    variable active $flag
    return
}

proc ::cmdr::color::active {} {
    debug.cmdr/color {}
    variable active
    return  $active
}

proc ::cmdr::color::define {name spec} {
    debug.cmdr/color {}
    variable def
    variable char
    # TODO: spec may be
    # => reference to other color name, or
    # => raw control sequence, or
    # => RGB spec.

    # Syntax:
    # ref = anything already found as key in the database.
    # rgb = 
    # raw = 

    if {[dict exists $def $spec]} {
	if {$spec eq $name} {
	    return -code error \
		-errorcode [list CMDR COLOR CIRCLE $name] \
		"Rejected self-referential definition of \"$name\""
	}
	debug.cmdr/color {reference, resolved => [S [dict get $char $spec]]}
	dict set def  $name $spec
	dict set char $name [dict get $char $spec]
	return
    }

    if {[regexp {^%(\d+),(\d+),(\d+)$} $spec -> r g b]} {
	# R, G, B all in range 0..5
	set r [Clamp $r]
	set g [Clamp $g]
	set b [Clamp $b]
	# 256 mapping
	# code = 16 + 36R + 6G + B --> [16..236]
	set code [expr {16 + 36*$r + 6*$g + $b}]
	debug.cmdr/color {RGB encoded => [S [C $code]]}
	dict set def  $name $spec
	dict set char $name [C $code]
	return

	# Legacy mapping
	# R,G,B mapping 0,1 --> 0, 2,3 --> 1, 4,5 --> 2
	# bold mapping: 0,1,2 --> 0,1,1 (set if any of R, G, B)
	# code = 8bold + R + 2G + 4B
	#      = 8, for R==G==B != 0, special case.
    }

    # Raw control sequence, simply save
    dict set def  $name $spec
    dict set char $name $spec
    return
}

# # ## ### ##### ######## ############# #####################

proc ::cmdr::color::Unknown {cmd codes text} {
    list [namespace current]::Apply $codes
}

proc ::cmdr::color::Apply {codes text} {
    debug.cmdr/color {}

    variable active
    if {!$active} {
	debug.cmdr/color {not active}
	return $text
    }

    variable char
    foreach c $codes {
	if {[dict exists $char $c]} {
	    return -code error \
		-errorcode [list CMDR COLOR UNKNOWN $c] \
		"Expected a color name, got \"$c\""
	}
	append r [dict get $char $c]
    }
    append r $text
    append r [dict get $char reset]

    debug.cmdr/color {/done}
    return $r
}

proc ::cmdr::color::S {text} {
    # quote all non-printable characters (< space, > ~)
    variable smap
    return [string map $smap $text]
}

proc ::cmdr::color::C {args} {
    return \033\[[join $args \;]m
}

proc ::cmdr::color::Clamp {x} {
    if {$x < 0} { return 0 }
    if {$x > 5} { return 5 }
    return $x
}

# # ## ### ##### ######## ############# #####################

namespace eval ::cmdr::color {
    # Boolean flag controlling use of color sequences.
    # Default based on tty-ness of stdout. Active if yes.
    variable active [tty stdout]

    # Database (dictionary) of standard colors and associated codes.
    # Based on the standard ANSI colors (16-color terminal). The two
    # dictionaries hold the user-level specification and the
    # full-resolved character sequence.

    variable def  {}
    variable char {}

    # Colors. Foreground/Text.
    define  black        [C 30]  ; # Black  
    define  red          [C 31]  ; # Red    
    define  green        [C 32]  ; # Green  
    define  yellow       [C 33]  ; # Yellow 
    define  blue         [C 34]  ; # Blue   
    define  magenta      [C 35]  ; # Magenta
    define  cyan         [C 36]  ; # Cyan   
    define  white        [C 37]  ; # White  
    define  default      [C 39]  ; # Default (Black)

    # Colors. Background.
    define  bg-black     [C 40]  ; # Black  
    define  bg-red       [C 41]  ; # Red    
    define  bg-green     [C 42]  ; # Green  
    define  bg-yellow    [C 43]  ; # Yellow 
    define  bg-blue      [C 44]  ; # Blue   
    define  bg-magenta   [C 45]  ; # Magenta
    define  bg-cyan      [C 46]  ; # Cyan   
    define  bg-white     [C 47]  ; # White  
    define  bg-default   [C 49]  ; # Default (Transparent)

    # Non-color attributes. Activation.
    define  bold         [C  1]  ; # Bold  
    define  dim          [C  2]  ; # Dim
    define  italic       [C  3]  ; # Italics      
    define  underline    [C  4]  ; # Underscore   
    define  blink        [C  5]  ; # Blink
    define  revers       [C  7]  ; # Reverse      
    define  hidden       [C  8]  ; # Hidden
    define  strike       [C  9]  ; # StrikeThrough

    # Non-color attributes. Deactivation.
    define  no-bold      [C 22]  ; # Bold  
    define  no-dim       [C __]  ; # Dim
    define  no-italic    [C 23]  ; # Italics      
    define  no-underline [C 24]  ; # Underscore   
    define  no-blink     [C 25]  ; # Blink
    define  no-revers    [C 27]  ; # Reverse      
    define  no-hidden    [C 28]  ; # Hidden
    define  no-strike    [C 29]  ; # StrikeThrough

    # Remainder
    define  reset        [C  0]  ; # Reset

    # And now the standard symbolic names

    define  confirm red
    define  error   red
    define  warning yellow
    define  note    blue
    define  good    green
    define  name    blue

    # header command stopped advisory crashed failure success name prompt table warning
    # bl/whi bl/yel  bl/grey bl/yel   bl/red  bl/red  bl/gre  bl/cy bl/cy bl/cy bl/mag
    # stdout - white, stderr - red
    # app-header sys-header
    # bl/yel     bl/cy

    # others ...
    # name	<>	blue,
    # neutral	<>	blue,
    # good	<>	green,
    # bad	<>	red,
    # error	<>	magenta,
    # unknown	<>	cyan,
    # warning	<>	yellow,
    # instance<>	yellow,
    # number	<>	green,
    # prompt	<>	blue,
    # yes	<>	green,
    # no	<>	red

    variable smap {}
}

apply {{} {
    variable smap
    for {set i 0} {$i < 32} {incr i} {
	set c [format %c $i]
	set o \\[format %03o $i] 
	lappend smap $c $o
    }
    lappend smap \127 \\127
}} ::cmdr::color

# # ## ### ##### ######## ############# #####################
## Ready
package provide cmdr::color 0
Added tty.tcl.
























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
## -*- tcl -*-
# # ## ### ##### ######## ############# #####################
## CMDR - TTY. Convenience command for checking if stdout is a tty.

# @@ Meta Begin
# Package cmdr::tty 0
# Meta author   {Andreas Kupries}
# Meta location https://core.tcl.tk/akupries/cmdr
# Meta platform tcl
# Meta summary     Check if stdout is a TTY.
# Meta description 
# Meta subject {command line} tty
# Meta require {Tcl 8.5-}
# Meta require Tclx
# Meta require debug
# Meta require debug::caller
# @@ Meta End

# # ## ### ##### ######## ############# #####################
## Requisites

package require Tcl 8.5
package require Tclx
package require debug
package require debug::caller

# # ## ### ##### ######## #############

namespace eval ::cmdr {
    namespace export tty
    namespace ensemble create
}

namespace eval ::cmdr::tty {
    namespace export stdout
    namespace ensemble create
}

# # ## ### ##### ######## ############# #####################

debug define cmdr/tty
debug level  cmdr/tty
debug prefix cmdr/tty {[debug caller] | }

# # ## ### ##### ######## #############

if {$::tcl_platform(platform) eq "windows"} {
    proc ::cmdr::tty::stdout {} {
	debug.cmdr/tty {-- windows --}
	return 0
    }
} else {
    proc ::cmdr::tty::stdout {} {
	debug.cmdr/tty {-- unix/osx --}
	fstat stdout tty
    }
}

# # ## ### ##### ######## #############
package provide tty 0