[aspect] - I'm not a big fan of [IDE]s. Give me [Vim] and a shell and a REPL, such as [Tkcon]. To make Tkcon a better IDE I've developed some tools to make working between [Tkcon] and [Vim] much nicer. Hopefully others can use and improve these, and contribute their own inventions. ---- [LV] 2008 July 16 - what does [REPL] stand for? [AM] Read-Evaluate-Print Loop - the basic mode of working for a shell. ---- This toolkit allows you to start `gvim` from `tkcon`, with Tcl variables, arrays and procs, just by typing `vi procname`. When you save the file in `gvim`, it is evaluated in the running Tkcon. Suggested for use with the MiniBufExplorer vim plugin. First, a few dependencies: * [String channels] -- behave like files but store data in memory ---- * Namespace FTPD: [Tcllib]'s [ftpd] package set up so that you can retrieve procs, arrays and variables from a running Tcl. It makes use of Tkcon's `dump` proc, which is really useful but also easily duplicated (or copied from Tkcon sources). '''WARNING''': this performs '''no authentication''' so it's really dangerous on any networked system. Any file uploaded to this FTP server '''will be executed as Tcl code in the running interp'''! Call this file `nsftpd.tcl`. ====== # TODO: evaluate uploaded code in the appropriate namespace # TODO: return ensembles for namespaces # TODO: user authentication package require ftpd package require schan package provide nsftpd 0.1 namespace eval nsfscmd { proc append {path} { error "Not implemented: append " } proc delete {path channel} { error "Not implemented: delete " } proc dlist {path style channel} { set ns [string map {/ ""} $path] # puts "dlist $path $style $channel (::$ns)" set procs [namespace eval ::$ns {info procs}] set vars [namespace eval ::$ns {info vars}] set dirs [namespace eval ::$ns {namespace children}] foreach i [concat $dirs $vars $procs] { puts -nonewline $channel $i\r\n } } proc exists {path} { return 1 } proc mtime {path channel} { # puts "mtime $path $channel" puts $channel "2008-05-10 21:50" } proc size {path channel} { # puts "size $path $channel" puts $channel "200 1337" } proc permissions {path} { # puts "perms $path" return 0750 } proc rename {path newpath channel} { error "Not implemented: rename " } proc mkdir {path channel} { error "Not implemented: mkdir " } proc rmdir {path channel} { error "Not implemented: rmdir " } proc retr {path mode} { # puts "retr $path $mode" # puts "path $path" set ns [string trim [file dirname $path] /] # puts "ns $ns" set path [string trim $path /] # puts "path $path" set name [string range $path [expr 1+[string length $ns]] end] # puts "name $name" set ns [string map {/ ""} $ns] # puts "ns $ns" set fd [chan create [list read write] schan] fconfigure $fd -buffering none -translation {binary binary} # puts "dumping ${ns}::$name" puts $fd [dump ${ns}::$name] return $fd } proc receive {fd s} { # puts "receive $fd $s" uplevel #0 $s } proc store {path mode} { # puts "store $path $mode" set fd [chan create [list read write] schan] fconfigure $fd -buffering none -translation {binary binary} schan setccb $fd ::nsfscmd::receive return $fd } namespace export * namespace ensemble create } proc true args { return 1 } proc start_nsftpd {port} { ::ftpd::config -authUsrCmd true -authFileCmd true -fsCmd nsfscmd set dir [uplevel 1 namespace current] set dir [string map {:: /::} $dir] set ::ftpd::port $port set ::ftpd::cwd $dir ::ftpd::server } ====== ---- Finally, `proc vim`: ====== # vim.tcl -- # # A little utility for Tkcon to start vim on files, variables, procs, ... package require nsftpd package provide vim 0.2 namespace eval ::vim { proc edfile {fn} { exec gvim --servername TkCon --remote $fn & } proc edtclftp {fn} { exec gvim --servername TkCon --remote ftp://localhost:1337$fn & } proc ed {name} { set tclname [uplevel #0 "namespace which $name"] if {"" == $tclname} { set tclname [uplevel #0 "namespace which -var $name"] } puts "ed $name $tclname" if {"" != $tclname} { edtclftp [string map {:: /} $tclname] } else { edfile $name } } namespace export ed variable port 1337 proc init {} { package require nsftpd variable port puts -nonewline "<*> Starting FTP server on port $port:" uplevel 1 start_nsftpd $port puts " done!" } } interp alias {} vi {} ::vim::ed ::vim::init ====== ---- [jdb] 2009/11/12 - I have never been able to get the above version to work completely. My gvim hangs after logging in. I can edit files using ftpd through gvim so it must be something in the nsftpd layer above. Here is an alternate version, just a slightly modified vfs::ns to allow for writing. One key difference is that the gvim servername is tied to the tkcon pid and the ftpd port is dynamically generated so you can run this in multiple tkcon sessions and each uses it's own gvim session. Same warnings as above, no authentication and evals contents into interp. ====== package require ftpd package require vfs::ns proc vfs::ns::open {ns name mode permissions} { ::vfs::log "open $name $mode $permissions" # return a list of two elements: # 1. first element is the Tcl channel name which has been opened # 2. second element (optional) is a command to evaluate when # the channel is closed. switch -- $mode { "" - "r" { set nfd [vfs::memchan] fconfigure $nfd -translation binary puts -nonewline $nfd [_generate ::${ns}::${name}] fconfigure $nfd -translation auto seek $nfd 0 return [list $nfd] } "w" { set nfd [vfs::memchan] fconfigure $nfd -translation auto return [list $nfd [list vfs::ns::do_close $nfd $ns $name]] } default { return -code error "illegal access mode \"$mode\"" } } } proc vfs::ns::do_close { nfd ns name } { seek $nfd 0 eval [read $nfd] close $nfd } proc vi { proc_name } { exec gvim --servername TkCon-[pid] --remote ftp://localhost:$::ftpd::port/$proc_name & return } vfs::ns::Mount :: /nsvfs proc do_log { args } { } proc true { args } { return 1 } ftpd::config -authUsrCmd true -authFileCmd true -logCmd do_log set ::ftpd::port 0 set ::ftpd::cwd /nsvfs ftpd::server ====== <> Debugging | Dev. Tools