mirror of
https://github.com/maaslalani/slides.git
synced 2026-01-07 21:43:58 -05:00
doc: add comments to top of public functions and variables
This commit is contained in:
@@ -1,89 +1,91 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/maaslalani/slides/internal/model"
|
||||
"github.com/maaslalani/slides/internal/navigation"
|
||||
"github.com/maaslalani/slides/internal/server"
|
||||
"github.com/muesli/coral"
|
||||
"github.com/maaslalani/slides/internal/model"
|
||||
"github.com/maaslalani/slides/internal/navigation"
|
||||
"github.com/maaslalani/slides/internal/server"
|
||||
"github.com/muesli/coral"
|
||||
)
|
||||
|
||||
var (
|
||||
host string
|
||||
port int
|
||||
keyPath string
|
||||
err error
|
||||
fileName string
|
||||
|
||||
ServeCmd = &coral.Command{
|
||||
Use: "serve <file.md>",
|
||||
Aliases: []string{"server"},
|
||||
Short: "Start an SSH server to run slides",
|
||||
Args: coral.ArbitraryArgs,
|
||||
RunE: func(cmd *coral.Command, args []string) error {
|
||||
k := os.Getenv("SLIDES_SERVER_KEY_PATH")
|
||||
if k != "" {
|
||||
keyPath = k
|
||||
}
|
||||
h := os.Getenv("SLIDES_SERVER_HOST")
|
||||
if h != "" {
|
||||
host = h
|
||||
}
|
||||
p := os.Getenv("SLIDES_SERVER_PORT")
|
||||
if p != "" {
|
||||
port, _ = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
fileName = args[0]
|
||||
}
|
||||
|
||||
presentation := model.Model{
|
||||
Page: 0,
|
||||
Date: time.Now().Format("2006-01-02"),
|
||||
FileName: fileName,
|
||||
Search: navigation.NewSearch(),
|
||||
}
|
||||
err = presentation.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := server.NewServer(keyPath, host, port, presentation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done := make(chan os.Signal, 1)
|
||||
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Printf("Starting Slides server on %s:%d", host, port)
|
||||
go func() {
|
||||
if err = s.Start(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-done
|
||||
log.Print("Stopping Slides server")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer func() { cancel() }()
|
||||
if err := s.Shutdown(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
},
|
||||
}
|
||||
host string
|
||||
port int
|
||||
keyPath string
|
||||
err error
|
||||
fileName string
|
||||
)
|
||||
|
||||
func init() {
|
||||
ServeCmd.Flags().StringVar(&keyPath, "keyPath", "slides", "Server private key path")
|
||||
ServeCmd.Flags().StringVar(&host, "host", "localhost", "Server host to bind to")
|
||||
ServeCmd.Flags().IntVar(&port, "port", 53531, "Server port to bind to")
|
||||
// ServeCmd is the command for serving the presentation. It starts the slides
|
||||
// server allowing for connections.
|
||||
var ServeCmd = &coral.Command{
|
||||
Use: "serve <file.md>",
|
||||
Aliases: []string{"server"},
|
||||
Short: "Start an SSH server to run slides",
|
||||
Args: coral.ArbitraryArgs,
|
||||
RunE: func(cmd *coral.Command, args []string) error {
|
||||
k := os.Getenv("SLIDES_SERVER_KEY_PATH")
|
||||
if k != "" {
|
||||
keyPath = k
|
||||
}
|
||||
h := os.Getenv("SLIDES_SERVER_HOST")
|
||||
if h != "" {
|
||||
host = h
|
||||
}
|
||||
p := os.Getenv("SLIDES_SERVER_PORT")
|
||||
if p != "" {
|
||||
port, _ = strconv.Atoi(p)
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
fileName = args[0]
|
||||
}
|
||||
|
||||
presentation := model.Model{
|
||||
Page: 0,
|
||||
Date: time.Now().Format("2006-01-02"),
|
||||
FileName: fileName,
|
||||
Search: navigation.NewSearch(),
|
||||
}
|
||||
err = presentation.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := server.NewServer(keyPath, host, port, presentation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done := make(chan os.Signal, 1)
|
||||
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||
log.Printf("Starting Slides server on %s:%d", host, port)
|
||||
go func() {
|
||||
if err = s.Start(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-done
|
||||
log.Print("Stopping Slides server")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer func() { cancel() }()
|
||||
if err := s.Shutdown(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
ServeCmd.Flags().StringVar(&keyPath, "keyPath", "slides", "Server private key path")
|
||||
ServeCmd.Flags().StringVar(&host, "host", "localhost", "Server host to bind to")
|
||||
ServeCmd.Flags().IntVar(&port, "port", 53531, "Server port to bind to")
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Block represents a code block.
|
||||
type Block struct {
|
||||
Code string
|
||||
Language string
|
||||
}
|
||||
|
||||
// Result represents the output for an executed code block.
|
||||
type Result struct {
|
||||
Out string
|
||||
ExitCode int
|
||||
@@ -26,6 +28,9 @@ type Result struct {
|
||||
var re = regexp.MustCompile("(?s)(?:```|~~~)(\\w+)\n(.*?)\n(?:```|~~~)\\s?")
|
||||
|
||||
var (
|
||||
// ErrParse is the returned error when we cannot parse the code block (i.e.
|
||||
// there is no code block on the current slide) or the code block is
|
||||
// incorrectly written.
|
||||
ErrParse = errors.New("Error: could not parse code block")
|
||||
)
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ package code
|
||||
// Placeholders <file>, <name> and <path> can be used.
|
||||
type cmds [][]string
|
||||
|
||||
// ----
|
||||
|
||||
// Language represents a programming language with it Extension and Commands to
|
||||
// execute its programs.
|
||||
type Language struct {
|
||||
// Extension represents the file extension used by this language.
|
||||
Extension string
|
||||
// Commands [][]string // placeholders: <name> file name (without extension),
|
||||
// <file> file name, <path> path without file name
|
||||
// Commands [][]string // placeholders: <name> file name (without
|
||||
// extension), <file> file name, <path> path without file name
|
||||
Commands cmds
|
||||
}
|
||||
|
||||
@@ -26,6 +27,8 @@ const (
|
||||
Rust = "rust"
|
||||
)
|
||||
|
||||
// Languages is a map of supported languages with their extensions and commands
|
||||
// to run to execute the program.
|
||||
var Languages = map[string]Language{
|
||||
Bash: {
|
||||
Extension: "sh",
|
||||
|
||||
@@ -33,6 +33,8 @@ const (
|
||||
delimiter = "\n---\n"
|
||||
)
|
||||
|
||||
// Model represents the model of this presentation, which contains all the
|
||||
// state related to the current slides.
|
||||
type Model struct {
|
||||
Slides []string
|
||||
Page int
|
||||
@@ -53,6 +55,8 @@ type fileWatchMsg struct{}
|
||||
|
||||
var fileInfo os.FileInfo
|
||||
|
||||
// Init initializes the model and begins watching the slides file for changes
|
||||
// if it exists.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
if m.FileName == "" {
|
||||
return nil
|
||||
@@ -67,6 +71,7 @@ func fileWatchCmd() tea.Cmd {
|
||||
})
|
||||
}
|
||||
|
||||
// Load loads all of the content and metadata for the presentation.
|
||||
func (m *Model) Load() error {
|
||||
var content string
|
||||
var err error
|
||||
@@ -194,6 +199,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// View renders the current slide in the presentation and the status bar which
|
||||
// contains the author, date, and pagination information.
|
||||
func (m Model) View() string {
|
||||
r, _ := glamour.NewTermRenderer(m.Theme, glamour.WithWordWrap(m.viewport.Width))
|
||||
slide := m.Slides[m.Page]
|
||||
@@ -284,10 +291,12 @@ func readStdin() (string, error) {
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
// CurrentPage returns the current page the presentation is on.
|
||||
func (m *Model) CurrentPage() int {
|
||||
return m.Page
|
||||
}
|
||||
|
||||
// SetPage sets which page the presentation should render.
|
||||
func (m *Model) SetPage(page int) {
|
||||
if m.Page == page {
|
||||
return
|
||||
@@ -297,6 +306,7 @@ func (m *Model) SetPage(page int) {
|
||||
m.Page = page
|
||||
}
|
||||
|
||||
// Pages returns all the slides in the presentation.
|
||||
func (m *Model) Pages() []string {
|
||||
return m.Slides
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func navigateNext(state State) int {
|
||||
|
||||
func navigateSlide(buffer string, totalSlides int) int {
|
||||
destinationSlide, _ := strconv.Atoi(buffer)
|
||||
destinationSlide -= 1
|
||||
destinationSlide--
|
||||
|
||||
if destinationSlide > totalSlides-1 {
|
||||
return totalSlides - 1
|
||||
|
||||
@@ -24,6 +24,7 @@ type Search struct {
|
||||
SearchTextInput textinput.Model
|
||||
}
|
||||
|
||||
// NewSearch creates and returns a new search model with the default settings.
|
||||
func NewSearch() Search {
|
||||
ti := textinput.NewModel()
|
||||
ti.Placeholder = "search"
|
||||
@@ -33,18 +34,19 @@ func NewSearch() Search {
|
||||
return Search{SearchTextInput: ti}
|
||||
}
|
||||
|
||||
// Query returns the text input's value.
|
||||
func (s *Search) Query() string {
|
||||
return s.SearchTextInput.Value()
|
||||
}
|
||||
|
||||
// SetQuery sets the text input's value
|
||||
func (s *Search) SetQuery(query string) {
|
||||
s.SearchTextInput.SetValue(query)
|
||||
}
|
||||
|
||||
// Mark Search as
|
||||
// Done - Do not delete search buffer
|
||||
// This is useful if, for example, you want to jump to the next result
|
||||
// and you therefore still need the buffer
|
||||
// Done marks the search as done, but does not delete the search buffer. This
|
||||
// is useful if, for example, you want to jump to the next result and you
|
||||
// therefore still need the buffer.
|
||||
func (s *Search) Done() {
|
||||
s.Active = false
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type Block struct {
|
||||
Raw string
|
||||
}
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (b Block) String() string {
|
||||
return fmt.Sprintf("===\n%s\n%s\n%s\n===", b.Raw, b.Command, b.Input)
|
||||
}
|
||||
|
||||
@@ -29,4 +29,3 @@ func slidesMiddleware(srv *Server) wish.Middleware {
|
||||
}
|
||||
return bm.MiddlewareWithProgramHandler(teaHandler, termenv.ANSI256)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,18 +9,19 @@ import (
|
||||
"github.com/maaslalani/slides/internal/model"
|
||||
)
|
||||
|
||||
// Server is the server for hosting this presentation.
|
||||
type Server struct {
|
||||
host string
|
||||
port int
|
||||
srv *ssh.Server
|
||||
host string
|
||||
port int
|
||||
srv *ssh.Server
|
||||
presentation model.Model
|
||||
}
|
||||
|
||||
// NewServer creates a new server.
|
||||
func NewServer(keyPath, host string, port int, presentation model.Model) (*Server, error) {
|
||||
s := &Server{
|
||||
host: host,
|
||||
port: port,
|
||||
host: host,
|
||||
port: port,
|
||||
presentation: presentation,
|
||||
}
|
||||
srv, err := wish.NewServer(
|
||||
|
||||
2
main.go
2
main.go
@@ -16,7 +16,7 @@ var (
|
||||
rootCmd = &coral.Command{
|
||||
Use: "slides <file.md>",
|
||||
Short: "Terminal based presentation tool",
|
||||
Args: coral.ArbitraryArgs,
|
||||
Args: coral.ArbitraryArgs,
|
||||
RunE: func(cmd *coral.Command, args []string) error {
|
||||
var err error
|
||||
var fileName string
|
||||
|
||||
@@ -18,35 +18,41 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Author is the style for the author text in the bottom-left corner of the
|
||||
// presentation.
|
||||
Author = lipgloss.NewStyle().Foreground(salmon).Align(lipgloss.Left).MarginLeft(2)
|
||||
Date = lipgloss.NewStyle().Faint(true).Align(lipgloss.Left).Margin(0, 1)
|
||||
Page = lipgloss.NewStyle().Foreground(salmon).Align(lipgloss.Right).MarginRight(3)
|
||||
Slide = lipgloss.NewStyle().Padding(1)
|
||||
// Date is the style for the date text in the bottom-left corner of the
|
||||
// presentation.
|
||||
Date = lipgloss.NewStyle().Faint(true).Align(lipgloss.Left).Margin(0, 1)
|
||||
// Page is the style for the pagination progress information text in the
|
||||
// bottom-right corner of the presentation.
|
||||
Page = lipgloss.NewStyle().Foreground(salmon).Align(lipgloss.Right).MarginRight(3)
|
||||
// Slide is the style for the slide.
|
||||
Slide = lipgloss.NewStyle().Padding(1)
|
||||
// Status is the style for the status bar at the bottom of the
|
||||
// presentation.
|
||||
Status = lipgloss.NewStyle().Padding(1)
|
||||
// Search is the style for the search input at the bottom-left corner of
|
||||
// the screen when searching is active.
|
||||
Search = lipgloss.NewStyle().Faint(true).Align(lipgloss.Left).MarginLeft(2)
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTheme is the default theme for the presentation.
|
||||
//go:embed theme.json
|
||||
DefaultTheme []byte
|
||||
)
|
||||
|
||||
// JoinHorizontal joins two strings horizontally and fills the space in-between.
|
||||
func JoinHorizontal(left, right string, width int) string {
|
||||
length := lipgloss.Width(left + right)
|
||||
if width < length {
|
||||
return left + " " + right
|
||||
}
|
||||
padding := strings.Repeat(" ", width-length)
|
||||
return left + padding + right
|
||||
w := width - lipgloss.Width(right)
|
||||
return lipgloss.PlaceHorizontal(w, lipgloss.Left, left) + right
|
||||
}
|
||||
|
||||
// JoinVertical joins two strings vertically and fills the space in-between.
|
||||
func JoinVertical(top, bottom string, height int) string {
|
||||
h := lipgloss.Height(top) + lipgloss.Height(bottom)
|
||||
if height < h {
|
||||
return top + "\n" + bottom
|
||||
}
|
||||
fill := strings.Repeat("\n", height-h)
|
||||
return top + fill + bottom
|
||||
h := height - lipgloss.Height(bottom)
|
||||
return lipgloss.PlaceVertical(h, lipgloss.Top, top) + bottom
|
||||
}
|
||||
|
||||
// SelectTheme picks a glamour style config based
|
||||
|
||||
Reference in New Issue
Block a user