From 58d4b020cc4bbe0d6460310d3a95740ad87cd63b Mon Sep 17 00:00:00 2001 From: Maas Lalani Date: Wed, 9 Jun 2021 09:46:29 -0400 Subject: [PATCH 1/2] Read slides from `stdin` Fixes #15 This change allows users to pipe in slides from `stdin` which allows for `curl`ing remote slides and presenting them as well as piping multiple files into one (with `cat`) and much more. ``` curl http://example.com/slides.md | slides ``` This change also maintains backwards compatibility with the current API which allows for users to simply specify a file name. In the future, it would be nice to remove that in favour of simply reading the file from stdin. Like so: ``` slides < examples/slides.md ``` --- cmd/root.go | 70 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 072a747..6e331d1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,12 +1,15 @@ package cmd import ( + "bufio" "errors" "fmt" + "io" "io/ioutil" "os" "os/user" "strings" + "time" tea "github.com/charmbracelet/bubbletea" "github.com/maaslalani/slides/internal/model" @@ -21,24 +24,21 @@ const ( var root = &cobra.Command{ Use: "slides ", Short: "Slides is a terminal based presentation tool", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(1), RunE: func(_ *cobra.Command, args []string) error { - f := args[0] + var content string + var err error + + if len(args) > 0 { + content, err = readFile(args[0]) + } else { + content, err = readStdin() + } - s, err := os.Stat(f) if err != nil { - return errors.New("could not read file") - } - if s.IsDir() { - return errors.New("must pass a file") + return err } - b, err := ioutil.ReadFile(f) - if err != nil { - return errors.New("could not read file") - } - - content := string(b) content = strings.ReplaceAll(content, altDelimiter, delimiter) slides := strings.Split(content, delimiter) @@ -51,7 +51,7 @@ var root = &cobra.Command{ Slides: slides, Page: 0, Author: user.Name, - Date: s.ModTime().Format("2006-01-02"), + Date: time.Now().Format("2006-01-02"), }, tea.WithAltScreen()) err = p.Start() @@ -66,3 +66,45 @@ func Execute() { os.Exit(1) } } + +func readFile(path string) (string, error) { + s, err := os.Stat(path) + if err != nil { + return "", errors.New("could not read file") + } + if s.IsDir() { + return "", errors.New("can not read directory") + } + b, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + return string(b), err +} + +func readStdin() (string, error) { + stat, err := os.Stdin.Stat() + if err != nil { + return "", err + } + + if stat.Mode()&os.ModeNamedPipe == 0 && stat.Size() == 0 { + return "", errors.New("no slides provided") + } + + reader := bufio.NewReader(os.Stdin) + var b strings.Builder + + for { + r, _, err := reader.ReadRune() + if err != nil && err == io.EOF { + break + } + _, err = b.WriteRune(r) + if err != nil { + return "", err + } + } + + return b.String(), nil +} From 3da723872f7c95948646b7dd72df3f45c35fc390 Mon Sep 17 00:00:00 2001 From: Maas Lalani Date: Wed, 9 Jun 2021 09:46:58 -0400 Subject: [PATCH 2/2] Documentation: stdin and curling remote slides --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 84ace1b..44c050f 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,11 @@ Then, to present, run: slides presentation.md ``` +You are also able to pass in slides through `stdin`, this allows you to `curl` and present remote files: +``` +curl https://example.com/slides.md | slides +``` + Go to the next slide with any of the following keys: * space * right