Version 0 of Tkcon as an IDE shell

Updated 2008-07-16 11:43:28 by aspect

aspect - I'm not a big fan of IDEs. 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.

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:


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