sqlitecon.tcl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. # A Tk console widget for SQLite. Invoke sqlitecon::create with a window name,
  2. # a prompt string, a title to set a new top-level window, and the SQLite
  3. # database handle. For example:
  4. #
  5. # sqlitecon::create .sqlcon {sql:- } {SQL Console} db
  6. #
  7. # A toplevel window is created that allows you to type in SQL commands to
  8. # be processed on the spot.
  9. #
  10. # A limited set of dot-commands are supported:
  11. #
  12. # .table
  13. # .schema ?TABLE?
  14. # .mode list|column|multicolumn|line
  15. # .exit
  16. #
  17. # In addition, a new SQL function named "edit()" is created. This function
  18. # takes a single text argument and returns a text result. Whenever the
  19. # the function is called, it pops up a new toplevel window containing a
  20. # text editor screen initialized to the argument. When the "OK" button
  21. # is pressed, whatever revised text is in the text editor is returned as
  22. # the result of the edit() function. This allows text fields of SQL tables
  23. # to be edited quickly and easily as follows:
  24. #
  25. # UPDATE table1 SET dscr = edit(dscr) WHERE rowid=15;
  26. #
  27. # Create a namespace to work in
  28. #
  29. namespace eval ::sqlitecon {
  30. # do nothing
  31. }
  32. # Create a console widget named $w. The prompt string is $prompt.
  33. # The title at the top of the window is $title. The database connection
  34. # object is $db
  35. #
  36. proc sqlitecon::create {w prompt title db} {
  37. upvar #0 $w.t v
  38. if {[winfo exists $w]} {destroy $w}
  39. if {[info exists v]} {unset v}
  40. toplevel $w
  41. wm title $w $title
  42. wm iconname $w $title
  43. frame $w.mb -bd 2 -relief raised
  44. pack $w.mb -side top -fill x
  45. menubutton $w.mb.file -text File -menu $w.mb.file.m
  46. menubutton $w.mb.edit -text Edit -menu $w.mb.edit.m
  47. pack $w.mb.file $w.mb.edit -side left -padx 8 -pady 1
  48. set m [menu $w.mb.file.m -tearoff 0]
  49. $m add command -label {Close} -command "destroy $w"
  50. sqlitecon::create_child $w $prompt $w.mb.edit.m
  51. set v(db) $db
  52. $db function edit ::sqlitecon::_edit
  53. }
  54. # This routine creates a console as a child window within a larger
  55. # window. It also creates an edit menu named "$editmenu" if $editmenu!="".
  56. # The calling function is responsible for posting the edit menu.
  57. #
  58. proc sqlitecon::create_child {w prompt editmenu} {
  59. upvar #0 $w.t v
  60. if {$editmenu!=""} {
  61. set m [menu $editmenu -tearoff 0]
  62. $m add command -label Cut -command "sqlitecon::Cut $w.t"
  63. $m add command -label Copy -command "sqlitecon::Copy $w.t"
  64. $m add command -label Paste -command "sqlitecon::Paste $w.t"
  65. $m add command -label {Clear Screen} -command "sqlitecon::Clear $w.t"
  66. $m add separator
  67. $m add command -label {Save As...} -command "sqlitecon::SaveFile $w.t"
  68. catch {$editmenu config -postcommand "sqlitecon::EnableEditMenu $w"}
  69. }
  70. scrollbar $w.sb -orient vertical -command "$w.t yview"
  71. pack $w.sb -side right -fill y
  72. text $w.t -font fixed -yscrollcommand "$w.sb set"
  73. pack $w.t -side right -fill both -expand 1
  74. bindtags $w.t Sqlitecon
  75. set v(editmenu) $editmenu
  76. set v(history) 0
  77. set v(historycnt) 0
  78. set v(current) -1
  79. set v(prompt) $prompt
  80. set v(prior) {}
  81. set v(plength) [string length $v(prompt)]
  82. set v(x) 0
  83. set v(y) 0
  84. set v(mode) column
  85. set v(header) on
  86. $w.t mark set insert end
  87. $w.t tag config ok -foreground blue
  88. $w.t tag config err -foreground red
  89. $w.t insert end $v(prompt)
  90. $w.t mark set out 1.0
  91. after idle "focus $w.t"
  92. }
  93. bind Sqlitecon <1> {sqlitecon::Button1 %W %x %y}
  94. bind Sqlitecon <B1-Motion> {sqlitecon::B1Motion %W %x %y}
  95. bind Sqlitecon <B1-Leave> {sqlitecon::B1Leave %W %x %y}
  96. bind Sqlitecon <B1-Enter> {sqlitecon::cancelMotor %W}
  97. bind Sqlitecon <ButtonRelease-1> {sqlitecon::cancelMotor %W}
  98. bind Sqlitecon <KeyPress> {sqlitecon::Insert %W %A}
  99. bind Sqlitecon <Left> {sqlitecon::Left %W}
  100. bind Sqlitecon <Control-b> {sqlitecon::Left %W}
  101. bind Sqlitecon <Right> {sqlitecon::Right %W}
  102. bind Sqlitecon <Control-f> {sqlitecon::Right %W}
  103. bind Sqlitecon <BackSpace> {sqlitecon::Backspace %W}
  104. bind Sqlitecon <Control-h> {sqlitecon::Backspace %W}
  105. bind Sqlitecon <Delete> {sqlitecon::Delete %W}
  106. bind Sqlitecon <Control-d> {sqlitecon::Delete %W}
  107. bind Sqlitecon <Home> {sqlitecon::Home %W}
  108. bind Sqlitecon <Control-a> {sqlitecon::Home %W}
  109. bind Sqlitecon <End> {sqlitecon::End %W}
  110. bind Sqlitecon <Control-e> {sqlitecon::End %W}
  111. bind Sqlitecon <Return> {sqlitecon::Enter %W}
  112. bind Sqlitecon <KP_Enter> {sqlitecon::Enter %W}
  113. bind Sqlitecon <Up> {sqlitecon::Prior %W}
  114. bind Sqlitecon <Control-p> {sqlitecon::Prior %W}
  115. bind Sqlitecon <Down> {sqlitecon::Next %W}
  116. bind Sqlitecon <Control-n> {sqlitecon::Next %W}
  117. bind Sqlitecon <Control-k> {sqlitecon::EraseEOL %W}
  118. bind Sqlitecon <<Cut>> {sqlitecon::Cut %W}
  119. bind Sqlitecon <<Copy>> {sqlitecon::Copy %W}
  120. bind Sqlitecon <<Paste>> {sqlitecon::Paste %W}
  121. bind Sqlitecon <<Clear>> {sqlitecon::Clear %W}
  122. # Insert a single character at the insertion cursor
  123. #
  124. proc sqlitecon::Insert {w a} {
  125. $w insert insert $a
  126. $w yview insert
  127. }
  128. # Move the cursor one character to the left
  129. #
  130. proc sqlitecon::Left {w} {
  131. upvar #0 $w v
  132. scan [$w index insert] %d.%d row col
  133. if {$col>$v(plength)} {
  134. $w mark set insert "insert -1c"
  135. }
  136. }
  137. # Erase the character to the left of the cursor
  138. #
  139. proc sqlitecon::Backspace {w} {
  140. upvar #0 $w v
  141. scan [$w index insert] %d.%d row col
  142. if {$col>$v(plength)} {
  143. $w delete {insert -1c}
  144. }
  145. }
  146. # Erase to the end of the line
  147. #
  148. proc sqlitecon::EraseEOL {w} {
  149. upvar #0 $w v
  150. scan [$w index insert] %d.%d row col
  151. if {$col>=$v(plength)} {
  152. $w delete insert {insert lineend}
  153. }
  154. }
  155. # Move the cursor one character to the right
  156. #
  157. proc sqlitecon::Right {w} {
  158. $w mark set insert "insert +1c"
  159. }
  160. # Erase the character to the right of the cursor
  161. #
  162. proc sqlitecon::Delete w {
  163. $w delete insert
  164. }
  165. # Move the cursor to the beginning of the current line
  166. #
  167. proc sqlitecon::Home w {
  168. upvar #0 $w v
  169. scan [$w index insert] %d.%d row col
  170. $w mark set insert $row.$v(plength)
  171. }
  172. # Move the cursor to the end of the current line
  173. #
  174. proc sqlitecon::End w {
  175. $w mark set insert {insert lineend}
  176. }
  177. # Add a line to the history
  178. #
  179. proc sqlitecon::addHistory {w line} {
  180. upvar #0 $w v
  181. if {$v(historycnt)>0} {
  182. set last [lindex $v(history) [expr $v(historycnt)-1]]
  183. if {[string compare $last $line]} {
  184. lappend v(history) $line
  185. incr v(historycnt)
  186. }
  187. } else {
  188. set v(history) [list $line]
  189. set v(historycnt) 1
  190. }
  191. set v(current) $v(historycnt)
  192. }
  193. # Called when "Enter" is pressed. Do something with the line
  194. # of text that was entered.
  195. #
  196. proc sqlitecon::Enter w {
  197. upvar #0 $w v
  198. scan [$w index insert] %d.%d row col
  199. set start $row.$v(plength)
  200. set line [$w get $start "$start lineend"]
  201. $w insert end \n
  202. $w mark set out end
  203. if {$v(prior)==""} {
  204. set cmd $line
  205. } else {
  206. set cmd $v(prior)\n$line
  207. }
  208. if {[string index $cmd 0]=="." || [$v(db) complete $cmd]} {
  209. regsub -all {\n} [string trim $cmd] { } cmd2
  210. addHistory $w $cmd2
  211. set rc [catch {DoCommand $w $cmd} res]
  212. if {![winfo exists $w]} return
  213. if {$rc} {
  214. $w insert end $res\n err
  215. } elseif {[string length $res]>0} {
  216. $w insert end $res\n ok
  217. }
  218. set v(prior) {}
  219. $w insert end $v(prompt)
  220. } else {
  221. set v(prior) $cmd
  222. regsub -all {[^ ]} $v(prompt) . x
  223. $w insert end $x
  224. }
  225. $w mark set insert end
  226. $w mark set out {insert linestart}
  227. $w yview insert
  228. }
  229. # Execute a single SQL command. Pay special attention to control
  230. # directives that begin with "."
  231. #
  232. # The return value is the text output from the command, properly
  233. # formatted.
  234. #
  235. proc sqlitecon::DoCommand {w cmd} {
  236. upvar #0 $w v
  237. set mode $v(mode)
  238. set header $v(header)
  239. if {[regexp {^(\.[a-z]+)} $cmd all word]} {
  240. if {$word==".mode"} {
  241. regexp {^.[a-z]+ +([a-z]+)} $cmd all v(mode)
  242. return {}
  243. } elseif {$word==".exit"} {
  244. destroy [winfo toplevel $w]
  245. return {}
  246. } elseif {$word==".header"} {
  247. regexp {^.[a-z]+ +([a-z]+)} $cmd all v(header)
  248. return {}
  249. } elseif {$word==".tables"} {
  250. set mode multicolumn
  251. set cmd {SELECT name FROM sqlite_master WHERE type='table'
  252. UNION ALL
  253. SELECT name FROM sqlite_temp_master WHERE type='table'}
  254. $v(db) eval {PRAGMA database_list} {
  255. if {$name!="temp" && $name!="main"} {
  256. append cmd "UNION ALL SELECT name FROM $name.sqlite_master\
  257. WHERE type='table'"
  258. }
  259. }
  260. append cmd { ORDER BY 1}
  261. } elseif {$word==".fullschema"} {
  262. set pattern %
  263. regexp {^.[a-z]+ +([^ ]+)} $cmd all pattern
  264. set mode list
  265. set header 0
  266. set cmd "SELECT sql FROM sqlite_master WHERE tbl_name LIKE '$pattern'
  267. AND sql NOT NULL UNION ALL SELECT sql FROM sqlite_temp_master
  268. WHERE tbl_name LIKE '$pattern' AND sql NOT NULL"
  269. $v(db) eval {PRAGMA database_list} {
  270. if {$name!="temp" && $name!="main"} {
  271. append cmd " UNION ALL SELECT sql FROM $name.sqlite_master\
  272. WHERE tbl_name LIKE '$pattern' AND sql NOT NULL"
  273. }
  274. }
  275. } elseif {$word==".schema"} {
  276. set pattern %
  277. regexp {^.[a-z]+ +([^ ]+)} $cmd all pattern
  278. set mode list
  279. set header 0
  280. set cmd "SELECT sql FROM sqlite_master WHERE name LIKE '$pattern'
  281. AND sql NOT NULL UNION ALL SELECT sql FROM sqlite_temp_master
  282. WHERE name LIKE '$pattern' AND sql NOT NULL"
  283. $v(db) eval {PRAGMA database_list} {
  284. if {$name!="temp" && $name!="main"} {
  285. append cmd " UNION ALL SELECT sql FROM $name.sqlite_master\
  286. WHERE name LIKE '$pattern' AND sql NOT NULL"
  287. }
  288. }
  289. } else {
  290. return \
  291. ".exit\n.mode line|list|column\n.schema ?TABLENAME?\n.tables"
  292. }
  293. }
  294. set res {}
  295. if {$mode=="list"} {
  296. $v(db) eval $cmd x {
  297. set sep {}
  298. foreach col $x(*) {
  299. append res $sep$x($col)
  300. set sep |
  301. }
  302. append res \n
  303. }
  304. if {[info exists x(*)] && $header} {
  305. set sep {}
  306. set hdr {}
  307. foreach col $x(*) {
  308. append hdr $sep$col
  309. set sep |
  310. }
  311. set res $hdr\n$res
  312. }
  313. } elseif {[string range $mode 0 2]=="col"} {
  314. set y {}
  315. $v(db) eval $cmd x {
  316. foreach col $x(*) {
  317. if {![info exists cw($col)] || $cw($col)<[string length $x($col)]} {
  318. set cw($col) [string length $x($col)]
  319. }
  320. lappend y $x($col)
  321. }
  322. }
  323. if {[info exists x(*)] && $header} {
  324. set hdr {}
  325. set ln {}
  326. set dash ---------------------------------------------------------------
  327. append dash ------------------------------------------------------------
  328. foreach col $x(*) {
  329. if {![info exists cw($col)] || $cw($col)<[string length $col]} {
  330. set cw($col) [string length $col]
  331. }
  332. lappend hdr $col
  333. lappend ln [string range $dash 1 $cw($col)]
  334. }
  335. set y [concat $hdr $ln $y]
  336. }
  337. if {[info exists x(*)]} {
  338. set format {}
  339. set arglist {}
  340. set arglist2 {}
  341. set i 0
  342. foreach col $x(*) {
  343. lappend arglist x$i
  344. append arglist2 " \$x$i"
  345. incr i
  346. append format " %-$cw($col)s"
  347. }
  348. set format [string trimleft $format]\n
  349. if {[llength $arglist]>0} {
  350. foreach $arglist $y "append res \[format [list $format] $arglist2\]"
  351. }
  352. }
  353. } elseif {$mode=="multicolumn"} {
  354. set y [$v(db) eval $cmd]
  355. set max 0
  356. foreach e $y {
  357. if {$max<[string length $e]} {set max [string length $e]}
  358. }
  359. set ncol [expr {int(80/($max+2))}]
  360. if {$ncol<1} {set ncol 1}
  361. set nelem [llength $y]
  362. set nrow [expr {($nelem+$ncol-1)/$ncol}]
  363. set format "%-${max}s"
  364. for {set i 0} {$i<$nrow} {incr i} {
  365. set j $i
  366. while 1 {
  367. append res [format $format [lindex $y $j]]
  368. incr j $nrow
  369. if {$j>=$nelem} break
  370. append res { }
  371. }
  372. append res \n
  373. }
  374. } else {
  375. $v(db) eval $cmd x {
  376. foreach col $x(*) {append res "$col = $x($col)\n"}
  377. append res \n
  378. }
  379. }
  380. return [string trimright $res]
  381. }
  382. # Change the line to the previous line
  383. #
  384. proc sqlitecon::Prior w {
  385. upvar #0 $w v
  386. if {$v(current)<=0} return
  387. incr v(current) -1
  388. set line [lindex $v(history) $v(current)]
  389. sqlitecon::SetLine $w $line
  390. }
  391. # Change the line to the next line
  392. #
  393. proc sqlitecon::Next w {
  394. upvar #0 $w v
  395. if {$v(current)>=$v(historycnt)} return
  396. incr v(current) 1
  397. set line [lindex $v(history) $v(current)]
  398. sqlitecon::SetLine $w $line
  399. }
  400. # Change the contents of the entry line
  401. #
  402. proc sqlitecon::SetLine {w line} {
  403. upvar #0 $w v
  404. scan [$w index insert] %d.%d row col
  405. set start $row.$v(plength)
  406. $w delete $start end
  407. $w insert end $line
  408. $w mark set insert end
  409. $w yview insert
  410. }
  411. # Called when the mouse button is pressed at position $x,$y on
  412. # the console widget.
  413. #
  414. proc sqlitecon::Button1 {w x y} {
  415. global tkPriv
  416. upvar #0 $w v
  417. set v(mouseMoved) 0
  418. set v(pressX) $x
  419. set p [sqlitecon::nearestBoundry $w $x $y]
  420. scan [$w index insert] %d.%d ix iy
  421. scan $p %d.%d px py
  422. if {$px==$ix} {
  423. $w mark set insert $p
  424. }
  425. $w mark set anchor $p
  426. focus $w
  427. }
  428. # Find the boundry between characters that is nearest
  429. # to $x,$y
  430. #
  431. proc sqlitecon::nearestBoundry {w x y} {
  432. set p [$w index @$x,$y]
  433. set bb [$w bbox $p]
  434. if {![string compare $bb ""]} {return $p}
  435. if {($x-[lindex $bb 0])<([lindex $bb 2]/2)} {return $p}
  436. $w index "$p + 1 char"
  437. }
  438. # This routine extends the selection to the point specified by $x,$y
  439. #
  440. proc sqlitecon::SelectTo {w x y} {
  441. upvar #0 $w v
  442. set cur [sqlitecon::nearestBoundry $w $x $y]
  443. if {[catch {$w index anchor}]} {
  444. $w mark set anchor $cur
  445. }
  446. set anchor [$w index anchor]
  447. if {[$w compare $cur != $anchor] || (abs($v(pressX) - $x) >= 3)} {
  448. if {$v(mouseMoved)==0} {
  449. $w tag remove sel 0.0 end
  450. }
  451. set v(mouseMoved) 1
  452. }
  453. if {[$w compare $cur < anchor]} {
  454. set first $cur
  455. set last anchor
  456. } else {
  457. set first anchor
  458. set last $cur
  459. }
  460. if {$v(mouseMoved)} {
  461. $w tag remove sel 0.0 $first
  462. $w tag add sel $first $last
  463. $w tag remove sel $last end
  464. update idletasks
  465. }
  466. }
  467. # Called whenever the mouse moves while button-1 is held down.
  468. #
  469. proc sqlitecon::B1Motion {w x y} {
  470. upvar #0 $w v
  471. set v(y) $y
  472. set v(x) $x
  473. sqlitecon::SelectTo $w $x $y
  474. }
  475. # Called whenever the mouse leaves the boundries of the widget
  476. # while button 1 is held down.
  477. #
  478. proc sqlitecon::B1Leave {w x y} {
  479. upvar #0 $w v
  480. set v(y) $y
  481. set v(x) $x
  482. sqlitecon::motor $w
  483. }
  484. # This routine is called to automatically scroll the window when
  485. # the mouse drags offscreen.
  486. #
  487. proc sqlitecon::motor w {
  488. upvar #0 $w v
  489. if {![winfo exists $w]} return
  490. if {$v(y)>=[winfo height $w]} {
  491. $w yview scroll 1 units
  492. } elseif {$v(y)<0} {
  493. $w yview scroll -1 units
  494. } else {
  495. return
  496. }
  497. sqlitecon::SelectTo $w $v(x) $v(y)
  498. set v(timer) [after 50 sqlitecon::motor $w]
  499. }
  500. # This routine cancels the scrolling motor if it is active
  501. #
  502. proc sqlitecon::cancelMotor w {
  503. upvar #0 $w v
  504. catch {after cancel $v(timer)}
  505. catch {unset v(timer)}
  506. }
  507. # Do a Copy operation on the stuff currently selected.
  508. #
  509. proc sqlitecon::Copy w {
  510. if {![catch {set text [$w get sel.first sel.last]}]} {
  511. clipboard clear -displayof $w
  512. clipboard append -displayof $w $text
  513. }
  514. }
  515. # Return 1 if the selection exists and is contained
  516. # entirely on the input line. Return 2 if the selection
  517. # exists but is not entirely on the input line. Return 0
  518. # if the selection does not exist.
  519. #
  520. proc sqlitecon::canCut w {
  521. set r [catch {
  522. scan [$w index sel.first] %d.%d s1x s1y
  523. scan [$w index sel.last] %d.%d s2x s2y
  524. scan [$w index insert] %d.%d ix iy
  525. }]
  526. if {$r==1} {return 0}
  527. if {$s1x==$ix && $s2x==$ix} {return 1}
  528. return 2
  529. }
  530. # Do a Cut operation if possible. Cuts are only allowed
  531. # if the current selection is entirely contained on the
  532. # current input line.
  533. #
  534. proc sqlitecon::Cut w {
  535. if {[sqlitecon::canCut $w]==1} {
  536. sqlitecon::Copy $w
  537. $w delete sel.first sel.last
  538. }
  539. }
  540. # Do a paste opeation.
  541. #
  542. proc sqlitecon::Paste w {
  543. if {[sqlitecon::canCut $w]==1} {
  544. $w delete sel.first sel.last
  545. }
  546. if {[catch {selection get -displayof $w -selection CLIPBOARD} topaste]
  547. && [catch {selection get -displayof $w -selection PRIMARY} topaste]} {
  548. return
  549. }
  550. if {[info exists ::$w]} {
  551. set prior 0
  552. foreach line [split $topaste \n] {
  553. if {$prior} {
  554. sqlitecon::Enter $w
  555. update
  556. }
  557. set prior 1
  558. $w insert insert $line
  559. }
  560. } else {
  561. $w insert insert $topaste
  562. }
  563. }
  564. # Enable or disable entries in the Edit menu
  565. #
  566. proc sqlitecon::EnableEditMenu w {
  567. upvar #0 $w.t v
  568. set m $v(editmenu)
  569. if {$m=="" || ![winfo exists $m]} return
  570. switch [sqlitecon::canCut $w.t] {
  571. 0 {
  572. $m entryconf Copy -state disabled
  573. $m entryconf Cut -state disabled
  574. }
  575. 1 {
  576. $m entryconf Copy -state normal
  577. $m entryconf Cut -state normal
  578. }
  579. 2 {
  580. $m entryconf Copy -state normal
  581. $m entryconf Cut -state disabled
  582. }
  583. }
  584. }
  585. # Prompt the user for the name of a writable file. Then write the
  586. # entire contents of the console screen to that file.
  587. #
  588. proc sqlitecon::SaveFile w {
  589. set types {
  590. {{Text Files} {.txt}}
  591. {{All Files} *}
  592. }
  593. set f [tk_getSaveFile -filetypes $types -title "Write Screen To..."]
  594. if {$f!=""} {
  595. if {[catch {open $f w} fd]} {
  596. tk_messageBox -type ok -icon error -message $fd
  597. } else {
  598. puts $fd [string trimright [$w get 1.0 end] \n]
  599. close $fd
  600. }
  601. }
  602. }
  603. # Erase everything from the console above the insertion line.
  604. #
  605. proc sqlitecon::Clear w {
  606. $w delete 1.0 {insert linestart}
  607. }
  608. # An in-line editor for SQL
  609. #
  610. proc sqlitecon::_edit {origtxt {title {}}} {
  611. for {set i 0} {[winfo exists .ed$i]} {incr i} continue
  612. set w .ed$i
  613. toplevel $w
  614. wm protocol $w WM_DELETE_WINDOW "$w.b.can invoke"
  615. wm title $w {Inline SQL Editor}
  616. frame $w.b
  617. pack $w.b -side bottom -fill x
  618. button $w.b.can -text Cancel -width 6 -command [list set ::$w 0]
  619. button $w.b.ok -text OK -width 6 -command [list set ::$w 1]
  620. button $w.b.cut -text Cut -width 6 -command [list ::sqlitecon::Cut $w.t]
  621. button $w.b.copy -text Copy -width 6 -command [list ::sqlitecon::Copy $w.t]
  622. button $w.b.paste -text Paste -width 6 -command [list ::sqlitecon::Paste $w.t]
  623. set ::$w {}
  624. pack $w.b.cut $w.b.copy $w.b.paste $w.b.can $w.b.ok\
  625. -side left -padx 5 -pady 5 -expand 1
  626. if {$title!=""} {
  627. label $w.title -text $title
  628. pack $w.title -side top -padx 5 -pady 5
  629. }
  630. text $w.t -bg white -fg black -yscrollcommand [list $w.sb set]
  631. pack $w.t -side left -fill both -expand 1
  632. scrollbar $w.sb -orient vertical -command [list $w.t yview]
  633. pack $w.sb -side left -fill y
  634. $w.t insert end $origtxt
  635. vwait ::$w
  636. if {[set ::$w]} {
  637. set txt [string trimright [$w.t get 1.0 end]]
  638. } else {
  639. set txt $origtxt
  640. }
  641. destroy $w
  642. return $txt
  643. }