Console.tcl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. # -*- mode: TCL; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
  2. #
  3. # $Id: Console.tcl,v 1.5 2008/02/27 22:17:28 hobbs Exp $
  4. #
  5. # Console.tcl --
  6. #
  7. # This code constructs the console window for an application.
  8. # It can be used by non-unix systems that do not have built-in
  9. # support for shells.
  10. #
  11. # This file was distributed as a part of Tk 4.1 by Sun
  12. # Microsystems, Inc. and subsequently modified by Expert
  13. # Interface Techonoligies and included as a part of Tix.
  14. #
  15. # Some of the functions in this file have been renamed from
  16. # using a "tk" prefix to a "tix" prefix to avoid namespace
  17. # conflict with the original file.
  18. #
  19. # Copyright (c) 1995-1996 Sun Microsystems, Inc.
  20. # Copyright (c) 1993-1999 Ioi Kim Lam.
  21. # Copyright (c) 2000-2001 Tix Project Group.
  22. #
  23. # See the file "docs/license.tcltk" for information on usage and
  24. # redistribution of the original file "console.tcl". These license
  25. # terms do NOT apply to other files in the Tix distribution.
  26. #
  27. # See the file "license.terms" for information on usage and
  28. # redistribution * of this file, and for a DISCLAIMER OF ALL
  29. # WARRANTIES.
  30. # tixConsoleInit --
  31. # This procedure constructs and configures the console windows.
  32. #
  33. # Arguments:
  34. # None.
  35. foreach fun {tkTextSetCursor} {
  36. if {![llength [info commands $fun]]} {
  37. tk::unsupported::ExposePrivateCommand $fun
  38. }
  39. }
  40. unset fun
  41. proc tixConsoleInit {} {
  42. global tcl_platform
  43. uplevel #0 set tixConsoleTextFont Courier
  44. uplevel #0 set tixConsoleTextSize 14
  45. set f [frame .f]
  46. set fontcb [tixComboBox $f.size -label "" -command "tixConsoleSetFont" \
  47. -variable tixConsoleTextFont \
  48. -options {
  49. entry.width 15
  50. listbox.height 5
  51. }]
  52. set sizecb [tixComboBox $f.font -label "" -command "tixConsoleSetFont" \
  53. -variable tixConsoleTextSize \
  54. -options {
  55. entry.width 4
  56. listbox.width 6
  57. listbox.height 5
  58. }]
  59. pack $fontcb $sizecb -side left
  60. pack $f -side top -fill x -padx 2 -pady 2
  61. foreach font {
  62. "Courier New"
  63. "Courier"
  64. "Helvetica"
  65. "Lucida"
  66. "Lucida Typewriter"
  67. "MS LineDraw"
  68. "System"
  69. "Times Roman"
  70. } {
  71. $fontcb subwidget listbox insert end $font
  72. }
  73. for {set s 6} {$s < 25} {incr s} {
  74. $sizecb subwidget listbox insert end $s
  75. }
  76. bind [$fontcb subwidget entry] <Escape> "focus .console"
  77. bind [$sizecb subwidget entry] <Escape> "focus .console"
  78. text .console -yscrollcommand ".sb set" -setgrid true \
  79. -highlightcolor [. cget -bg] -highlightbackground [. cget -bg]
  80. scrollbar .sb -command ".console yview" -highlightcolor [. cget -bg] \
  81. -highlightbackground [. cget -bg]
  82. pack .sb -side right -fill both
  83. pack .console -fill both -expand 1 -side left
  84. tixConsoleBind .console
  85. .console tag configure stderr -foreground red
  86. .console tag configure stdin -foreground blue
  87. focus .console
  88. wm protocol . WM_DELETE_WINDOW { wm withdraw . }
  89. wm title . "Console"
  90. flush stdout
  91. .console mark set output [.console index "end - 1 char"]
  92. tkTextSetCursor .console end
  93. .console mark set promptEnd insert
  94. .console mark gravity promptEnd left
  95. tixConsoleSetFont
  96. }
  97. proc tixConsoleSetFont {args} {
  98. if ![winfo exists .console] tixConsoleInit
  99. global tixConsoleTextFont tixConsoleTextSize
  100. set font -*-$tixConsoleTextFont-medium-r-normal-*-$tixConsoleTextSize-*-*-*-*-*-*-*
  101. .console config -font $font
  102. }
  103. # tixConsoleInvoke --
  104. # Processes the command line input. If the command is complete it
  105. # is evaled in the main interpreter. Otherwise, the continuation
  106. # prompt is added and more input may be added.
  107. #
  108. # Arguments:
  109. # None.
  110. proc tixConsoleInvoke {args} {
  111. if ![winfo exists .console] tixConsoleInit
  112. if {[.console dlineinfo insert] != {}} {
  113. set setend 1
  114. } else {
  115. set setend 0
  116. }
  117. set ranges [.console tag ranges input]
  118. set cmd ""
  119. if {$ranges != ""} {
  120. set pos 0
  121. while {[lindex $ranges $pos] != ""} {
  122. set start [lindex $ranges $pos]
  123. set end [lindex $ranges [incr pos]]
  124. append cmd [.console get $start $end]
  125. incr pos
  126. }
  127. }
  128. if {$cmd == ""} {
  129. tixConsolePrompt
  130. } elseif {[info complete $cmd]} {
  131. .console mark set output end
  132. .console tag delete input
  133. set err [catch {
  134. set result [interp record $cmd]
  135. } result]
  136. if {$result != ""} {
  137. if {$err} {
  138. .console insert insert "$result\n" stderr
  139. } else {
  140. .console insert insert "$result\n"
  141. }
  142. }
  143. tixConsoleHistory reset
  144. tixConsolePrompt
  145. } else {
  146. tixConsolePrompt partial
  147. }
  148. if {$setend} {
  149. .console yview -pickplace insert
  150. }
  151. }
  152. # tixConsoleHistory --
  153. # This procedure implements command line history for the
  154. # console. In general is evals the history command in the
  155. # main interpreter to obtain the history. The global variable
  156. # histNum is used to store the current location in the history.
  157. #
  158. # Arguments:
  159. # cmd - Which action to take: prev, next, reset.
  160. set histNum 1
  161. proc tixConsoleHistory {cmd} {
  162. if ![winfo exists .console] tixConsoleInit
  163. global histNum
  164. switch $cmd {
  165. prev {
  166. incr histNum -1
  167. if {$histNum == 0} {
  168. set cmd {history event [expr [history nextid] -1]}
  169. } else {
  170. set cmd "history event $histNum"
  171. }
  172. if {[catch {interp eval $cmd} cmd]} {
  173. incr histNum
  174. return
  175. }
  176. .console delete promptEnd end
  177. .console insert promptEnd $cmd {input stdin}
  178. }
  179. next {
  180. incr histNum
  181. if {$histNum == 0} {
  182. set cmd {history event [expr [history nextid] -1]}
  183. } elseif {$histNum > 0} {
  184. set cmd ""
  185. set histNum 1
  186. } else {
  187. set cmd "history event $histNum"
  188. }
  189. if {$cmd != ""} {
  190. catch {interp eval $cmd} cmd
  191. }
  192. .console delete promptEnd end
  193. .console insert promptEnd $cmd {input stdin}
  194. }
  195. reset {
  196. set histNum 1
  197. }
  198. }
  199. }
  200. # tixConsolePrompt --
  201. # This procedure draws the prompt. If tcl_prompt1 or tcl_prompt2
  202. # exists in the main interpreter it will be called to generate the
  203. # prompt. Otherwise, a hard coded default prompt is printed.
  204. #
  205. # Arguments:
  206. # partial - Flag to specify which prompt to print.
  207. proc tixConsolePrompt {{partial normal}} {
  208. if ![winfo exists .console] tixConsoleInit
  209. if {$partial == "normal"} {
  210. set temp [.console index "end - 1 char"]
  211. .console mark set output end
  212. if {[interp eval "info exists tcl_prompt1"]} {
  213. interp eval "eval \[set tcl_prompt1\]"
  214. } else {
  215. puts -nonewline "% "
  216. }
  217. } else {
  218. set temp [.console index output]
  219. .console mark set output end
  220. if {[interp eval "info exists tcl_prompt2"]} {
  221. interp eval "eval \[set tcl_prompt2\]"
  222. } else {
  223. puts -nonewline "> "
  224. }
  225. }
  226. flush stdout
  227. .console mark set output $temp
  228. tkTextSetCursor .console end
  229. .console mark set promptEnd insert
  230. .console mark gravity promptEnd left
  231. }
  232. # tixConsoleBind --
  233. # This procedure first ensures that the default bindings for the Text
  234. # class have been defined. Then certain bindings are overridden for
  235. # the class.
  236. #
  237. # Arguments:
  238. # None.
  239. proc tixConsoleBind {win} {
  240. if ![winfo exists .console] tixConsoleInit
  241. bindtags $win "$win Text . all"
  242. # Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
  243. # Otherwise, if a widget binding for one of these is defined, the
  244. # <KeyPress> class binding will also fire and insert the character,
  245. # which is wrong. Ditto for <Escape>.
  246. bind $win <Alt-KeyPress> {# nothing }
  247. bind $win <Meta-KeyPress> {# nothing}
  248. bind $win <Control-KeyPress> {# nothing}
  249. bind $win <Escape> {# nothing}
  250. bind $win <KP_Enter> {# nothing}
  251. bind $win <Tab> {
  252. tixConsoleInsert %W \t
  253. focus %W
  254. break
  255. }
  256. bind $win <Return> {
  257. %W mark set insert {end - 1c}
  258. tixConsoleInsert %W "\n"
  259. tixConsoleInvoke
  260. break
  261. }
  262. bind $win <Delete> {
  263. if {[%W tag nextrange sel 1.0 end] != ""} {
  264. %W tag remove sel sel.first promptEnd
  265. } else {
  266. if {[%W compare insert < promptEnd]} {
  267. break
  268. }
  269. }
  270. }
  271. bind $win <BackSpace> {
  272. if {[%W tag nextrange sel 1.0 end] != ""} {
  273. %W tag remove sel sel.first promptEnd
  274. } else {
  275. if {[%W compare insert <= promptEnd]} {
  276. break
  277. }
  278. }
  279. }
  280. foreach left {Control-a Home} {
  281. bind $win <$left> {
  282. if {[%W compare insert < promptEnd]} {
  283. tkTextSetCursor %W {insert linestart}
  284. } else {
  285. tkTextSetCursor %W promptEnd
  286. }
  287. break
  288. }
  289. }
  290. foreach right {Control-e End} {
  291. bind $win <$right> {
  292. tkTextSetCursor %W {insert lineend}
  293. break
  294. }
  295. }
  296. bind $win <Control-d> {
  297. if {[%W compare insert < promptEnd]} {
  298. break
  299. }
  300. }
  301. bind $win <Control-k> {
  302. if {[%W compare insert < promptEnd]} {
  303. %W mark set insert promptEnd
  304. }
  305. }
  306. bind $win <Control-t> {
  307. if {[%W compare insert < promptEnd]} {
  308. break
  309. }
  310. }
  311. bind $win <Meta-d> {
  312. if {[%W compare insert < promptEnd]} {
  313. break
  314. }
  315. }
  316. bind $win <Meta-BackSpace> {
  317. if {[%W compare insert <= promptEnd]} {
  318. break
  319. }
  320. }
  321. bind $win <Control-h> {
  322. if {[%W compare insert <= promptEnd]} {
  323. break
  324. }
  325. }
  326. foreach prev {Control-p Up} {
  327. bind $win <$prev> {
  328. tixConsoleHistory prev
  329. break
  330. }
  331. }
  332. foreach prev {Control-n Down} {
  333. bind $win <$prev> {
  334. tixConsoleHistory next
  335. break
  336. }
  337. }
  338. bind $win <Control-v> {
  339. if {[%W compare insert > promptEnd]} {
  340. catch {
  341. %W insert insert [selection get -displayof %W] {input stdin}
  342. %W see insert
  343. }
  344. }
  345. break
  346. }
  347. bind $win <Insert> {
  348. catch {tixConsoleInsert %W [selection get -displayof %W]}
  349. break
  350. }
  351. bind $win <KeyPress> {
  352. tixConsoleInsert %W %A
  353. break
  354. }
  355. foreach left {Control-b Left} {
  356. bind $win <$left> {
  357. if {[%W compare insert == promptEnd]} {
  358. break
  359. }
  360. tkTextSetCursor %W insert-1c
  361. break
  362. }
  363. }
  364. foreach right {Control-f Right} {
  365. bind $win <$right> {
  366. tkTextSetCursor %W insert+1c
  367. break
  368. }
  369. }
  370. bind $win <Control-Up> {
  371. %W yview scroll -1 unit
  372. break;
  373. }
  374. bind $win <Control-Down> {
  375. %W yview scroll 1 unit
  376. break;
  377. }
  378. bind $win <Prior> {
  379. %W yview scroll -1 pages
  380. }
  381. bind $win <Next> {
  382. %W yview scroll 1 pages
  383. }
  384. bind $win <F9> {
  385. eval destroy [winfo child .]
  386. source $tix_library/Console.tcl
  387. }
  388. foreach copy {F16 Meta-w Control-i} {
  389. bind $win <$copy> {
  390. if {[selection own -displayof %W] == "%W"} {
  391. clipboard clear -displayof %W
  392. catch {
  393. clipboard append -displayof %W [selection get -displayof %W]
  394. }
  395. }
  396. break
  397. }
  398. }
  399. foreach paste {F18 Control-y} {
  400. bind $win <$paste> {
  401. catch {
  402. set clip [selection get -displayof %W -selection CLIPBOARD]
  403. set list [split $clip \n\r]
  404. tixConsoleInsert %W [lindex $list 0]
  405. foreach x [lrange $list 1 end] {
  406. %W mark set insert {end - 1c}
  407. tixConsoleInsert %W "\n"
  408. tixConsoleInvoke
  409. tixConsoleInsert %W $x
  410. }
  411. }
  412. break
  413. }
  414. }
  415. }
  416. # tixConsoleInsert --
  417. # Insert a string into a text at the point of the insertion cursor.
  418. # If there is a selection in the text, and it covers the point of the
  419. # insertion cursor, then delete the selection before inserting. Insertion
  420. # is restricted to the prompt area.
  421. #
  422. # Arguments:
  423. # w - The text window in which to insert the string
  424. # s - The string to insert (usually just a single character)
  425. proc tixConsoleInsert {w s} {
  426. if ![winfo exists .console] tixConsoleInit
  427. if {[.console dlineinfo insert] != {}} {
  428. set setend 1
  429. } else {
  430. set setend 0
  431. }
  432. if {$s == ""} {
  433. return
  434. }
  435. catch {
  436. if {[$w compare sel.first <= insert]
  437. && [$w compare sel.last >= insert]} {
  438. $w tag remove sel sel.first promptEnd
  439. $w delete sel.first sel.last
  440. }
  441. }
  442. if {[$w compare insert < promptEnd]} {
  443. $w mark set insert end
  444. }
  445. $w insert insert $s {input stdin}
  446. if $setend {
  447. .console see insert
  448. }
  449. }
  450. # tixConsoleOutput --
  451. #
  452. # This routine is called directly by ConsolePutsCmd to cause a string
  453. # to be displayed in the console.
  454. #
  455. # Arguments:
  456. # dest - The output tag to be used: either "stderr" or "stdout".
  457. # string - The string to be displayed.
  458. proc tixConsoleOutput {dest string} {
  459. if ![winfo exists .console] tixConsoleInit
  460. if {[.console dlineinfo insert] != {}} {
  461. set setend 1
  462. } else {
  463. set setend 0
  464. }
  465. .console insert output $string $dest
  466. if $setend {
  467. .console see insert
  468. }
  469. }
  470. # tixConsoleExit --
  471. #
  472. # This routine is called by ConsoleEventProc when the main window of
  473. # the application is destroyed.
  474. #
  475. # Arguments:
  476. # None.
  477. proc tixConsoleExit {} {
  478. if ![winfo exists .console] tixConsoleInit
  479. exit
  480. }
  481. # Configure the default Tk console
  482. proc tixConsoleEvalAppend {inter} {
  483. global tixOption
  484. # A slave like the console interp has no global variables set!
  485. if {!$inter} {
  486. console hide
  487. # Change the menubar to Close the console instead of exiting
  488. # Your code must provide a way for the user to do a "console show"
  489. console eval {
  490. if {[winfo exists .menubar.file]} {
  491. .menubar.file entryconfigure "Hide Console" \
  492. -underline 0 \
  493. -label Close \
  494. -command [list wm withdraw .]
  495. .menubar.file entryconfigure Exit -state disabled
  496. }
  497. }
  498. }
  499. console eval ".option configure -font \{$tixOption(fixed_font)\}"
  500. console eval {
  501. if {[winfo exists .menubar.edit]} {
  502. .menubar.edit add sep
  503. .menubar.edit add command \
  504. -accelerator 'Ctrl+l' \
  505. -underline 0 \
  506. -label Clear \
  507. -command [list .console delete 1.0 end]
  508. bind .console <Control-Key-l> [list .console delete 1.0 end]
  509. }
  510. if {![winfo exists .menubar.font]} {
  511. set m .menubar.font
  512. menu $m -tearoff 0
  513. .menubar add cascade -menu .menubar.font \
  514. -underline 0 -label Options
  515. global _TixConsole
  516. set font [font actual [.console cget -font]]
  517. set pos [lsearch $font -family]
  518. set _TixConsole(font) [lindex $font [incr pos]]
  519. set pos [lsearch $font -size]
  520. set _TixConsole(size) [lindex $font [incr pos]]
  521. set pos [lsearch $font -weight]
  522. set _TixConsole(weight) [lindex $font [incr pos]]
  523. set allowed {System Fixedsys Terminal {MS Serif}
  524. {MS Sans Serif} Courier {Lucida Console} Tahoma
  525. Arial {Courier New} {Times New Roman}
  526. {Arial Black} Verdana Garamond {Arial Narrow}}
  527. .menubar.font add cascade -label Font -menu $m.font
  528. menu $m.font -tearoff 0
  529. foreach font [lsort [font families]] {
  530. if {[lsearch $allowed $font] < 0} {continue}
  531. $m.font add radiobutton -label $font \
  532. -variable _TixConsole(font) \
  533. -value $font \
  534. -command \
  535. ".console configure -font \"\{$font\} \$_TixConsole(size) \$_TixConsole(weight)\""
  536. }
  537. .menubar.font add cascade -label Size -menu $m.size
  538. menu $m.size -tearoff 0
  539. foreach size {8 9 10 12 14 16 18} {
  540. $m.size add radiobutton -label $size \
  541. -variable _TixConsole(size) \
  542. -value $size \
  543. -command \
  544. ".console configure -font \"\{\$_TixConsole(font)\} $size \$_TixConsole(weight)\""
  545. }
  546. .menubar.font add cascade -label Weight -menu $m.weight
  547. menu $m.weight -tearoff 0
  548. foreach weight {normal bold} {
  549. $m.weight add radiobutton -label [string totit $weight] \
  550. -variable _TixConsole(weight) \
  551. -value $weight \
  552. -command \
  553. ".console configure -font \"\{\$_TixConsole(font)\} \$_TixConsole(size) $weight\""
  554. }
  555. }
  556. }
  557. }