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
 | |
| }
 |