github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/atalk/atalk.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "io/ioutil" 12 "log" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "strings" 17 18 "9fans.net/go/acme" 19 ) 20 21 func usage() { 22 fmt.Fprintf(os.Stderr, "usage: atalk file.talk\n") 23 os.Exit(2) 24 } 25 26 func main() { 27 log.SetPrefix("aslide: ") 28 log.SetFlags(0) 29 flag.Usage = usage 30 flag.Parse() 31 32 if flag.NArg() != 1 { 33 usage() 34 } 35 file := flag.Arg(0) 36 37 w, err := acme.New() 38 if err != nil { 39 log.Fatal(err) 40 } 41 w.Name("/talk/" + strings.TrimSuffix(filepath.Base(file), ".talk")) 42 w.Write("tag", []byte(" − +")) 43 44 var slides [][]byte 45 reload := func() { 46 data, err := ioutil.ReadFile(flag.Arg(0)) 47 if err != nil { 48 log.Fatal(err) 49 } 50 51 data = append([]byte("\n"), data...) 52 slides = bytes.Split(data, []byte("\n#\n")) 53 for lineno, line := range strings.Split(string(slides[0]), "\n") { 54 f := strings.Fields(line) 55 if len(f) == 0 { 56 continue 57 } 58 if len(f) >= 2 && f[0] == "Font" { 59 w.Ctl("font " + f[1]) 60 continue 61 } 62 w.Errf("%s:%d: unknown directive: %s", file, lineno+1, line) 63 } 64 slides = slides[1:] 65 for len(slides) > 0 && len(bytes.TrimSpace(slides[len(slides)-1])) == 0 { 66 slides = slides[:len(slides)-1] 67 } 68 if len(slides) == 0 { 69 log.Fatal("no slides in file") 70 } 71 } 72 reload() 73 74 slideNum := 0 75 show := func() { 76 if slideNum >= len(slides) { 77 slideNum = len(slides) - 1 78 } 79 if slideNum < 0 { 80 slideNum = 0 81 } 82 w.Addr(",") 83 var slide []byte 84 if len(slides) > 0 { 85 slide = slides[slideNum] 86 } 87 slide = append([]byte{'\n'}, slide...) 88 slide = bytes.ReplaceAll(slide, []byte("\n"), []byte("\n\t")) 89 slide = append(slide, '\n') 90 w.Write("data", slide) 91 w.Addr("0") 92 w.Ctl("dot=addr") 93 w.Ctl("show") 94 w.Addr("$") 95 w.Ctl("dot=addr") 96 w.Ctl("clean") 97 } 98 show() 99 100 for e := range w.EventChan() { 101 switch e.C2 { 102 case 'x', 'X': // execute 103 switch string(e.Text) { 104 default: 105 w.WriteEvent(e) 106 107 case "Del": 108 w.Ctl("delete") 109 110 case "Get": 111 reload() 112 show() 113 114 case "Edit": 115 if err := exec.Command("B", file).Run(); err != nil { 116 w.Errf("B %s: %v\n", file, err) 117 } 118 119 case "+": 120 if slideNum+1 < len(slides) { 121 slideNum++ 122 show() 123 } 124 125 case "-", "−": 126 if slideNum > 0 { 127 slideNum-- 128 show() 129 } 130 } 131 } 132 } 133 }