8385f4bea6
saved state in current directory (obs from Ulrich Neumerkel).
486 lines
12 KiB
Tcl
486 lines
12 KiB
Tcl
#!/usr/bin/wish -f
|
|
# tkyap -- a TK shell for YAP
|
|
# $Locker: $
|
|
# $Log: not supported by cvs2svn $
|
|
# Revision 1.1.1.1 2001/04/09 19:53:46 vsc
|
|
# Imported sources
|
|
#
|
|
# Revision 1.1 1997/06/02 16:32:00 vsc
|
|
# Initial revision
|
|
#
|
|
# Revision 1.1 1994/01/26 17:23:18 rvr
|
|
# Luis Damas Version
|
|
#
|
|
# Created On : Wed Jan 26 17:21:54 1994
|
|
# Last Modified By: Nelma Moreira
|
|
# Last Modified On: Sat Feb 5 20:24:04 1994
|
|
# Update Count : 39
|
|
#
|
|
# HISTORY
|
|
|
|
set service 8081
|
|
|
|
set YapOptions "-h1000 -s1000"
|
|
|
|
#
|
|
set TextFont "*7x13*"
|
|
set version "97"
|
|
|
|
#option add "*text*Font" $TextFont
|
|
#option add "*message*Font" $TextFont
|
|
#option add "*list*Font" $TextFont
|
|
|
|
if {[file exists /vmlinuz]} {
|
|
set TextFont "*6x10*"
|
|
if {[file exists /home/luis/Yap94/linux]} {
|
|
set homeyap /home/luis/Yap94/linux
|
|
} else {
|
|
set homeyap .
|
|
}
|
|
set PrologCommand "$homeyap/yap $homeyap/startup.yss -c localhost $service $YapOptions"
|
|
set SolarisBug 0
|
|
} else {
|
|
set PrologCommand "ny -h8000 -s1000"
|
|
set SolarisBug 1
|
|
}
|
|
|
|
|
|
|
|
set MaxHistory 100
|
|
|
|
###############################################################################
|
|
# Launch Prolog Proccess
|
|
|
|
# create server
|
|
|
|
socket -server client_connection $service
|
|
|
|
proc client_connection {sock host lixo} {
|
|
global from_yap to_yap
|
|
set from_yap $sock
|
|
set to_yap $sock
|
|
puts "Got client $sock $host"
|
|
fconfigure $sock -blocking 0 -buffering none
|
|
fileevent $sock readable output_from_yap
|
|
}
|
|
|
|
|
|
# run yap in parallel
|
|
set pid [eval exec $PrologCommand &]
|
|
|
|
# make sure we kill Prolog when we are killed
|
|
|
|
# signal trap SIGINT {ExitTkYap}
|
|
|
|
|
|
proc ExitTkYap {} {
|
|
global pid
|
|
SaveHistory
|
|
exec kill $pid
|
|
exit
|
|
}
|
|
|
|
###############################################################################
|
|
# Create a mininal interface
|
|
|
|
#### create a terminal window with a scrollbar
|
|
|
|
frame .frame
|
|
|
|
text .frame.text -bg white -font $TextFont \
|
|
-yscrollcommand {.frame.scrollbarv set}
|
|
|
|
# insert wellcome message
|
|
|
|
.frame.text insert end "Welcome to the Tcl/Tk Interface to YAP! ($version)\n"
|
|
set iline {\n\n\n\n\n\n} ; # this is because of bug in solaris version
|
|
|
|
# add scrollbar
|
|
|
|
frame .frame.scrollframe -relief ridge -bd 2
|
|
scrollbar .frame.scrollbarv -command {.frame.text yview}
|
|
pack append .frame.scrollframe .frame.scrollbarv {top expand filly}
|
|
|
|
# pack text widget and scrollbar
|
|
|
|
pack append .frame \
|
|
.frame.text {left frame center expand fill} \
|
|
.frame.scrollframe {right frame center filly}
|
|
|
|
#### Menu ####
|
|
frame .menu -relief raised -borderwidth 1
|
|
#pack .menu1 -before .frame -side top -fill x
|
|
|
|
menubutton .menu.file -text "File" -menu .menu.file.m -underline 0
|
|
menu .menu.file.m
|
|
.menu.file.m add command -label "Consult" -command {ConsultFile} -underline 0
|
|
.menu.file.m add command -label "Reconsult" \
|
|
-command {ReconsultFile} -underline 0
|
|
.menu.file.m add separator
|
|
.menu.file.m add command -label "Exit" -command {ExitTkYap} -underline 0
|
|
|
|
menubutton .menu.exec -text "Execution" -menu .menu.exec.m -underline 0
|
|
menu .menu.exec.m
|
|
.menu.exec.m add command -label "Interrupt" \
|
|
-command {global tcl_mode; set tcl_mode 0; exec kill -SIGINT $pid}
|
|
.menu.exec.m add separator
|
|
.menu.exec.m add command -label "Statistics" -command {YapStats}
|
|
|
|
pack .menu.file .menu.exec -side left
|
|
|
|
menubutton .menu.help -text "Help" -menu .menu.help.m -underline 0
|
|
menu .menu.help.m
|
|
pack .menu.help -side right
|
|
|
|
#### pack panes together
|
|
pack append . \
|
|
.menu {top fillx frame n} \
|
|
.frame {left frame n}
|
|
|
|
|
|
proc ReconsultFile {} {
|
|
global to_yap
|
|
set file [FileSelect "File to Reconsult" "*.yap"]
|
|
if {$file!=""} {
|
|
puts $to_yap "reconsult('$file')."
|
|
flush $to_yap
|
|
}
|
|
}
|
|
proc ConsultFile {} {
|
|
global to_yap
|
|
set file [FileSelect "File to Consult" "*.yap"]
|
|
if {$file!=""} {
|
|
puts $to_yap "consult('$file')."
|
|
flush $to_yap
|
|
}
|
|
}
|
|
|
|
proc YapStats {} {
|
|
global to_yap from_yap
|
|
puts $to_yap "statistics."
|
|
flush $to_yap
|
|
}
|
|
|
|
############################################################################
|
|
# Handle input from the keyboard
|
|
|
|
# InputStart is index of start of input
|
|
set InputStart [.frame.text index {end - 1 chars}]
|
|
|
|
# create a read_only range of text
|
|
.frame.text tag add rdonly 0.0 "$InputStart -0 chars"
|
|
|
|
# prevent user from modifying previous text by jumping to end of text
|
|
.frame.text tag bind rdonly <Any-Key> {
|
|
if {[.frame.text compare insert < $InputStart]} {
|
|
.frame.text mark set insert end
|
|
}
|
|
}
|
|
|
|
# pass ^C to yap
|
|
bind .frame.text <Control-Key-c> {
|
|
set tcl_mode 0
|
|
.frame.text yview -pickplace end
|
|
exec kill -SIGINT $pid
|
|
}
|
|
|
|
|
|
# add Readline/Emacs like bindings
|
|
bind .frame.text <Control-Key-a> {
|
|
.frame.text mark set insert $InputStart
|
|
}
|
|
|
|
bind .frame.text <Control-Key-b> {
|
|
.frame.text mark set insert {insert -1 chars}
|
|
}
|
|
|
|
bind .frame.text <Control-Key-d> {
|
|
.frame.text delete insert
|
|
}
|
|
|
|
bind .frame.text <Control-Key-e> {
|
|
.frame.text mark set insert end
|
|
}
|
|
|
|
bind .frame.text <Control-Key-f> {
|
|
.frame.text mark set insert {insert +1 chars}
|
|
}
|
|
|
|
bind .frame.text <Control-Key-k> {
|
|
.frame.text delete insert "insert lineend"
|
|
}
|
|
|
|
bind .frame.text <Key-BackSpace> {
|
|
if {[.frame.text compare insert > $InputStart]} {
|
|
.frame.text delete "insert -1 chars"
|
|
}
|
|
}
|
|
|
|
bind .frame.text <Key-Delete> {
|
|
if {[.frame.text compare insert > $InputStart]} {
|
|
.frame.text delete "insert -1 chars"
|
|
}
|
|
}
|
|
|
|
# add history bindings
|
|
set history {}
|
|
set history_len 0
|
|
set history_dir [exec pwd]
|
|
|
|
if {[file isfile .yap_history]} {
|
|
set file [open "$history_dir/.yap_history"]
|
|
while {[gets $file s]>0} {
|
|
lappend history $s
|
|
incr history_len
|
|
}
|
|
close $file
|
|
}
|
|
set history_ind $history_len
|
|
|
|
proc SaveHistory {} {
|
|
global history_len history_ind history history_dir
|
|
set file [open "$history_dir/.yap_history" w]
|
|
for {set i 0} {$i<$history_len} {incr i} {
|
|
puts $file [lindex $history $i]
|
|
}
|
|
close $file
|
|
}
|
|
|
|
proc AddHistory {line} {
|
|
global history_len history_ind history MaxHistory
|
|
if {[string length $line]<3} {return}
|
|
set i [lsearch -exact $history $line]
|
|
if {$i>=0} {
|
|
set history [lreplace $history $i $i]
|
|
incr history_len -1
|
|
}
|
|
if {$history_len>$MaxHistory} {
|
|
set history [lreplace $history 0 0]
|
|
incr history_len -1
|
|
}
|
|
lappend history $line
|
|
incr history_len
|
|
set history_ind $history_len
|
|
}
|
|
|
|
bind .frame.text <Control-Key-p> {
|
|
if {$history_ind==$history_len} {
|
|
set CurrentLine [.frame.text get $InputStart "$InputStart lineend"]
|
|
}
|
|
if {$history_ind>0} {
|
|
incr history_ind -1
|
|
.frame.text delete $InputStart "$InputStart lineend"
|
|
.frame.text insert $InputStart [lindex $history $history_ind]
|
|
}
|
|
}
|
|
|
|
bind .frame.text <Control-Key-n> {
|
|
if {$history_ind<$history_len} {
|
|
incr history_ind
|
|
.frame.text delete $InputStart "$InputStart lineend"
|
|
if {$history_ind==$history_len} {
|
|
.frame.text insert $InputStart $CurrentLine
|
|
} else {
|
|
.frame.text insert $InputStart [lindex $history $history_ind]
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# catch the enter key and send the input line to yap
|
|
|
|
bind .frame.text <Key-Return> {HandleInputLine}
|
|
|
|
proc HandleInputLine {} {
|
|
global InputStart to_yap iline
|
|
set iline [.frame.text get $InputStart end]
|
|
# .frame.text insert end "\n"
|
|
AddHistory $iline
|
|
puts "sending: '$iline'"
|
|
puts -nonewline $to_yap "$iline"
|
|
flush $to_yap
|
|
set InputStart [.frame.text index end]
|
|
.frame.text tag add rdonly 1.0 "$InputStart -0 chars"
|
|
}
|
|
|
|
|
|
##############################################################################
|
|
# Handle output from Yap
|
|
|
|
set tcl_mode 0
|
|
set tcl_buf {}
|
|
|
|
proc out_filter {s} {
|
|
global tcl_mode tcl_buf InputStart iline SolarisBug
|
|
while {$s!=""} {
|
|
set i [string first \001 $s]
|
|
set j [string first \002 $s]
|
|
set xflag 0
|
|
if {$j>=0 && ($i==-1 || $j<$i) } {set xflag 1; set i $j}
|
|
set new_mode $tcl_mode
|
|
if {$i<0} {
|
|
set ch $s
|
|
set s ""
|
|
} else {
|
|
set ch [string range $s 0 [expr $i-1]]
|
|
set s [string range $s [expr $i+1] end]
|
|
if {$xflag==0} { set new_mode [expr 1-$tcl_mode] }
|
|
}
|
|
# puts "$i $j '$ch' '$s' $xflag"
|
|
if {$tcl_mode} {
|
|
append tcl_buf $ch
|
|
} else {
|
|
if {$SolarisBug} {
|
|
# under Solaris we get echo on the fisrt line sent to
|
|
# Yap. So remove it ...
|
|
if {[csubstr $ch 0 [string length $iline]]=="$iline"} {
|
|
set ch [string range $ch [string length $iline\r\n] end]
|
|
set SolarisBug 0
|
|
puts fixed
|
|
}
|
|
}
|
|
.frame.text insert "$InputStart" $ch
|
|
set ll [string length $ch]
|
|
set InputStart [.frame.text index "$InputStart +$ll chars"]
|
|
.frame.text tag add rdonly 1.0 "$InputStart -0 chars"
|
|
.frame.text yview -pickplace end
|
|
update idletasks
|
|
}
|
|
if {$xflag} {
|
|
puts "eval $tcl_buf"
|
|
flush stdout
|
|
set res [catch "eval $tcl_buf" errMsg ]
|
|
puts "$res $errMsg"
|
|
if {$res!=0} {
|
|
tkerror $errMsg
|
|
}
|
|
set tcl_buf {}
|
|
}
|
|
set tcl_mode $new_mode
|
|
}
|
|
}
|
|
|
|
# this is an idle task routine to handle output from yap
|
|
|
|
|
|
proc idle_task {} {
|
|
global from_yap
|
|
set got 0
|
|
while {$got<500} {
|
|
set fr [select [list $from_yap] {} {} 0.01]
|
|
set fr [lindex $fr 0]
|
|
#puts "fr=$fr"
|
|
if {$fr != {}} {
|
|
#puts "reading"
|
|
set ch [read $from_yap ]
|
|
incr got [string length $ch]
|
|
out_filter $ch
|
|
#puts "read '$ch'"
|
|
} else {
|
|
if {$got} { .frame.text yview -pickplace end }
|
|
flush stdout
|
|
break
|
|
}
|
|
}
|
|
after 100 idle_task
|
|
}
|
|
|
|
proc output_from_yap {} {
|
|
global from_yap
|
|
set ch [read $from_yap]
|
|
puts "got: '$ch'"
|
|
out_filter $ch
|
|
.frame.text yview -pickplace end
|
|
# fileevent $from_yap readable output_from_yap
|
|
update
|
|
}
|
|
|
|
#### File selection...
|
|
|
|
proc FileSelectOk {} {
|
|
global FileSelectRes
|
|
set FileSelectRes ok
|
|
}
|
|
|
|
proc FileSelectCancel {} {
|
|
global FileSelectRes
|
|
set FileSelectRes cancel
|
|
}
|
|
|
|
proc FileSelectUpdate {} {
|
|
global FileSelectFilter
|
|
set wd [exec pwd]
|
|
set dir [open "|ls -a"]
|
|
.fileSelect.list delete 0 end
|
|
while {[gets $dir f]>0} {
|
|
if {[file isdirectory $f]} {
|
|
.fileSelect.list insert end $f
|
|
} elseif {[string match $FileSelectFilter $f]} {
|
|
.fileSelect.list insert end $f
|
|
}
|
|
}
|
|
close $dir
|
|
.fileSelect.dir configure -text "Dir: $wd"
|
|
}
|
|
|
|
proc FileSelect {msg filter} {
|
|
global FileSelectRes FileSelectFilter
|
|
set FileSelectFilter $filter
|
|
if {[winfo exists .fileSelect]} {destroy .fileSelect}
|
|
toplevel .fileSelect
|
|
message .fileSelect.msg -text $msg -width 300
|
|
frame .fileSelect.lbox -relief raised -bd 2
|
|
listbox .fileSelect.list -bd 1 \
|
|
-yscrollcommand {.fileSelect.scroll set}
|
|
scrollbar .fileSelect.scroll -bd 2 -command {.fileSelect.list yview}
|
|
pack append .fileSelect.lbox \
|
|
.fileSelect.list {left expand fill} \
|
|
.fileSelect.scroll {right filly}
|
|
set wd [exec pwd]
|
|
label .fileSelect.dir -text "Directory: $wd "
|
|
frame .fileSelect.buttons
|
|
button .fileSelect.buttons.ok -text "Ok" -command "FileSelectOk"
|
|
button .fileSelect.buttons.cancel -text "Cancel" -command "FileSelectCancel"
|
|
pack .fileSelect.buttons.ok .fileSelect.buttons.cancel -side left -padx 10
|
|
pack append .fileSelect \
|
|
.fileSelect.msg {top expand fillx } \
|
|
.fileSelect.dir {expand fillx} \
|
|
.fileSelect.lbox {expand fillx} \
|
|
.fileSelect.buttons {expand fillx pady 5}
|
|
tk_listboxSingleSelect .fileSelect.list
|
|
bind .fileSelect.list <Double-ButtonRelease-1> "FileSelectOk"
|
|
set w .fileSelect
|
|
wm withdraw $w
|
|
update idletasks
|
|
set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
|
|
- [winfo vrootx [winfo parent $w]]]
|
|
set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
|
|
- [winfo vrooty [winfo parent $w]]]
|
|
wm geom $w +$x+$y
|
|
wm deiconify $w
|
|
set oldFocus [focus]
|
|
grab .fileSelect
|
|
while 1 {
|
|
set FileSelectRes {}
|
|
FileSelectUpdate
|
|
update
|
|
tkwait variable FileSelectRes
|
|
if {$FileSelectRes=="cancel"} {break}
|
|
set file [.fileSelect.list curselection ]
|
|
if {$file!=""} {
|
|
set file $wd/[.fileSelect.list get $file]
|
|
if {[file isdirectory $file]} {
|
|
set wd $file
|
|
cd $file
|
|
} else {break}
|
|
}
|
|
}
|
|
destroy .fileSelect
|
|
focus $oldFocus
|
|
if {$FileSelectRes=="cancel"} {
|
|
set file ""
|
|
cd $wd
|
|
}
|
|
return $file
|
|
}
|