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  }