Commits

Anonymous committed 78a3406

Added Win: opens an rc in an acme win at the location specified with a chord 2-1 (or to the xplor root by default)

  • Participants
  • Parent commits beadcf3

Comments (0)

Files changed (2)

+# Add this rule to your plumbing rules, for example on top, 
+# right after the declarations of ports without rules. ymmv.
+#
+# start rc in a win at the specified path from xplor
+type is text
+src is xplor
+dst is win
+plumb start win rc -c '@{cd '$data'; exec rc -l}'
+
 
 import (
 	"os"
+//	"bytes"
 	"path"
 	"fmt"
 	"strings"
 	"bitbucket.org/fhs/goplumb/plumb"
 )
 
-var root string
-var w *acme.Win
-var INDENT string = "	"
-var PLAN9 = os.Getenv("PLAN9")
+var (
+	root string
+	w *acme.Win
+	PLAN9 = os.Getenv("PLAN9")
+	unfolded map[int] string
+//	chartoline *List 
+)
 
-const NBUF = 512
-const dirflag = "+ "
+const (
+	NBUF = 512
+	INDENT = "	"
+	dirflag = "+ "
+)
 
+type dir struct  {
+	charaddr string
+	depth int
+}
+	
 func usage() {
 	fmt.Fprintf(os.Stderr, "usage: xplor [path] \n")
 	flag.PrintDefaults()
 	os.Exit(2)
 }
 
-//TODO: send error messages to +Errors instead of Stderr?
-//TODO: keep a list of unfolded  dirs
-// because it will be faster to go through that list and find the right parent for a file when constructing the fullpath, than going recursively up
+//TODO: send error messages to +Errors instead of Stderr? easy sol: start xplor from the acme tag
+//TODO: make a closeAll command ?
+//TODO: keep a list of unfolded  dirs because it will be faster to go through that list and find the right parent for a file when constructing the fullpath, than going recursively up. After some experimenting, it's not that easy to do, so I may as well make a full rework that uses a tree in memory to map the filesystem tree, rather than go all textual.
 
 func main() {
 	flag.Usage = usage
 		fmt.Fprintf(os.Stderr, err.String())
 		return
 	}
+//	unfolded = make(map[string] int, 1)
 
 	for word := range events() {
 		if word == "DotDot" {
 			onExec(word[1:len(word)])
 			continue
 		}
+		if len(word) >= 3 {
+			if word[0:3] == "Win" {
+				doWin(word[3:len(word)])
+				continue
+			}
+		}
 		onLook(word)
 	}
 }
 
+/*
+func initCharToLine(lines int) (err os.Error) {
+	b := make([]byte, 64)
+	var (
+		m, n int
+		addr string = "#1+1-"
+	)
+	chartoline.Init() 
+
+	for i:= 0; i < lines; i++ {
+		err = w.Addr("%s", addr)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, err.String())
+			os.Exit(1)
+		}
+		n, err = w.Read("xdata", b)
+		if err != nil && err != os.EOF{
+			fmt.Fprintf(os.Stderr, err.String())
+			os.Exit(1)
+		}
+		m += n
+		print(m, "\n")
+		chartoline[i] = m
+		addr = "#" + fmt.Sprint(m+1) + "+1-"
+	}
+	for i:= 0; i < lines; i++ {
+		print(i, ": ", chartoline[i], "\n")
+	}
+	return err
+}
+*/
+
 func initWindow() os.Error {
 	var err os.Error = nil
 	w, err = acme.New()
 
 	title := "xplor-" + root
 	w.Name(title)
-	tag := "DotDot"
+	tag := "DotDot Win"
 	w.Write("tag", []byte(tag))
-	return printDirContents(root, 0)
+	_, err = printDirContents(root, 0)
+//	initCharToLine(len(newlines))
+	return err
 }
 
-func printDirContents(dirpath string, depth int) os.Error {
+func printDirContents(dirpath string, depth int) (newlines []int, err os.Error) {
+	var m int
 	currentDir, err := os.Open(dirpath, os.O_RDONLY, 0644)
 	if err != nil {
-		return err
+		return newlines, err
 	}
 	names, err := currentDir.Readdirnames(-1)
 	if err != nil {
-		return err
+		return newlines, err
 	}
 	currentDir.Close()
 
 			fullpath := path.Join(dirpath, v)
 			fi, err := os.Lstat(fullpath)
 			if err != nil {
-				return err
+				return newlines, err
 			}
 			if fi.IsDirectory() {
-				w.Write("data", []byte(dirflag+indents+v+"\n"))
+				m, _ = w.Write("data", []byte(dirflag+indents+v+"\n"))
+				newlines = append(newlines, m)
 			}
 		} else {
-			w.Write("data", []byte("  "+indents+v+"\n"))
+			m, _ = w.Write("data", []byte("  "+indents+v+"\n"))
+			newlines = append(newlines, m)
 		}
 	}
 
+	if depth == 0 {
 	//lame trick for now to dodge the out of range issue, until my address-foo gets better
-	if depth == 0 {
 		w.Write("body", []byte("\n"))
 		w.Write("body", []byte("\n"))
 		w.Write("body", []byte("\n"))
-	}
-	return err
+	} 
+
+	return newlines, err
 }
 
 func readLine(addr string) ([]byte, os.Error) {
 	return (nextdepth <= depth), err
 }
 
+/*
+func getParent(line string) string {
+	d, leaf := getDepth(line)
+	var parent string 
+	for k, v := range unfolded {
+			fullpath := path.Join(k, leaf)
+			fi, err := os.Lstat(fullpath)
+			if err == nil {
+			fmt.Fprintf(os.Stderr, err.String())
+		return
+	}		
+		dist, _ := strconv.Atoi(v.charaddr)
+		dist-= pos
+		if dist > 0 && dist < min {
+			depth, _ := getDepth(b)
+			if v.depth == depth - 1 {
+				min = dist
+				parent = k
+			}
+		}
+	}
+	print(parent, "\n")
+	return parent
+}
+*/
+
 func getParents(charaddr string, depth int, prevline int) string {
 	var addr string
 	if depth == 0 {
 	return ""
 }
 
+/*
+func addToCharToLine(newlines []int, where int) {
+	for i:=0; i<len(newlines); i++ {
+		print(newlines[i], " ")
+	}
+}
+
+//IDEA: get the offset from the total size before and after the folding
+func removeFromCharToLine([]newLines, offset) {
+
+}
+
+func addToUnfolded(fullpath string, newdir dir) os.Error {
+	_, ok := unfolded[fullpath]
+	if ok {
+		errstring := fullpath + " already in list"
+		return os.NewError(errstring)
+	}
+	unfolded[fullpath] = newdir
+	for k,v := range unfolded {
+		print(k, " ", v.charaddr, " ", v.depth, "\n")
+	}
+	print("\n")
+	return nil
+}
+
+//TODO: remove all the children as well
+func removeFromUnfolded(fullpath string) os.Error {
+	for k, _ := range unfolded {
+		if strings.Contains(k, fullpath) {
+			unfolded[k] = dir{}, false
+		}
+	}
+	for k,v := range unfolded {
+		print(k, " ", v.charaddr, " ", v.depth, "\n")
+	}
+	print("\n")
+	return nil
+}
+*/
+
 //TODO: maybe break this one in a fold and unfold functions
 func onLook(charaddr string) {
 	// reconstruct full path and check if file or dir
 	}
 	depth, line := getDepth(b)
 	fullpath := path.Join(root, getParents(charaddr, depth, 1), line)
+//	fullpath := path.Join(root, getParent(charaddr), line)
 	fi, err := os.Lstat(fullpath)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, err.String())
 			return
 		}
 		printDirContents(fullpath, depth+1)
+//		newlines, _ := printDirContents(fullpath, depth+1)
+//		addToCharToLine(newlines, 1)
+//		addToUnfolded(fullpath, dir{charaddr, depth})
 	} else {
-		// unfold, ie delete lines below dir until we hit a dir of the same depth
+		// fold, ie delete lines below dir until we hit a dir of the same depth
 		addr = "#" + charaddr + "+-"
 		nextdepth := depth + 1
 		nextline := 1
 			return
 		}
 		w.Write("data", []byte(""))
+//		removeFromUnfolded(charaddr)
 	}
 }
 
+//TODO: deal with errors
+func getFullPath(charaddr string) (fullpath string, err os.Error) {
+	// reconstruct full path and print it to Stdout
+	addr := "#" + charaddr + "+1-"
+	b, err := readLine(addr)
+	if err != nil {
+		return fullpath, err
+	}
+	depth, line := getDepth(b)
+	fullpath = path.Join(root, getParents(charaddr, depth, 1), line)
+//	fullpath = path.Join(root, getParent(charaddr), line)
+	return fullpath, err
+}
+
 func doDotDot() {
 	// blank the window
 	err := w.Addr("0,$")
 	root = path.Clean(root + "/../")
 	title := "xplor-" + root
 	w.Name(title)
-	err = printDirContents(root, 0)
+	_, err = printDirContents(root, 0)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, err.String())
 		os.Exit(1)
 	}
 }
 
+// For this function to work as intended, it needs to be coupled with a
+// plumbing rule, such as:
+// # start rc from xplor in an acme win at the specified path 
+// type is text
+// src is xplor
+// dst is win
+// plumb start win rc -c '@{cd '$data'; exec rc -l}'
+func doWin(loc string) {
+	print("loc: ", loc, "\n")
+	var fullpath string
+	if loc == "" {
+		fullpath = root
+	} else {
+		var err os.Error
+		charaddr := strings.SplitAfter(loc, ",#", 2) 
+		fullpath, err = getFullPath(charaddr[1])
+			print("fullpath0: ", fullpath, "\n")
+		if err != nil {
+			fmt.Fprintf(os.Stderr, err.String())
+			return
+		}
+		fi, err := os.Lstat(fullpath)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, err.String())
+			return
+		}
+		if !fi.IsDirectory() {
+			fullpath, _ = path.Split(fullpath)
+			print("fullpath1: ", fullpath, "\n")
+		}
+	}
+	print("fullpath: ", fullpath, "\n")
+	// send the fullpath as a win command to the plumber
+	port, err := plumb.Open("send", plan9.OWRITE)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, err.String())
+		return
+	}
+	defer port.Close()
+	port.Send(&plumb.Msg{
+		Src:  "xplor",
+		Dst:  "win",
+		WDir: "/",
+		Kind: "text",
+		Attr: map[string]string{},
+		Data: []byte(fullpath),
+	})
+	return
+}
+
 // on a B2 click event we print the fullpath of the file to Stdout.
 // This can come in handy for paths with spaces in it, because the
 // plumber will fail to open them.  Printing it to Stdout allows us to do
 // Also usefull with a dir path: once printed to stdout, a B3 click on
 // the path to open it the "classic" acme way.
 func onExec(charaddr string) {
-	// reconstruct full path and print it to Stdout
-	addr := "#" + charaddr + "+1-"
-	b, err := readLine(addr)
+	fullpath, err := getFullPath(charaddr)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, err.String())
 		return
 	}
-	depth, line := getDepth(b)
-	fullpath := path.Join(root, getParents(charaddr, depth, 1), line)
 	fmt.Fprintf(os.Stderr, fullpath+"\n")
 }
 
 					w.Ctl("delete")
 				case "DotDot":
 					c <- "DotDot"
+				case "Win":
+					tmp := ""
+					if e.Flag != 0 {
+						tmp = string(e.Loc)
+					}
+					c <- ("Win" + tmp)
 				default:
 					w.WriteEvent(e)
 				}