// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//modify 2013-2014 visualfc
package gopresent
import (
"fmt"
"html/template"
"io"
"os"
"path/filepath"
"github.com/visualfc/gotools/command"
"golang.org/x/tools/present"
)
var Command = &command.Command{
Run: runPresent,
UsageLine: "gopresent",
Short: "golang present util",
Long: `golang present util`,
}
var presentVerifyOnly bool
var presentInput string
var presentStdout bool
var presentOutput string
func init() {
Command.Flag.BoolVar(&presentVerifyOnly, "v", false, "verify present only")
Command.Flag.BoolVar(&presentStdout, "stdout", false, "output use std output")
Command.Flag.StringVar(&presentInput, "i", "", "input golang present file")
Command.Flag.StringVar(&presentOutput, "o", "", "output html file name")
}
func runPresent(cmd *command.Command, args []string) error {
if presentInput == "" || !isDoc(presentInput) {
cmd.Usage()
return os.ErrInvalid
}
if presentVerifyOnly {
err := VerifyDoc(presentInput)
if err != nil {
fmt.Fprintf(os.Stderr, "present:%s", err)
command.SetExitStatus(3)
command.Exit()
}
return nil
}
w := os.Stdout
if !presentStdout {
if presentOutput == "" {
presentOutput = presentInput + ".html"
}
ext := filepath.Ext(presentOutput)
if ext != ".htm" && ext != ".html" {
presentOutput += ".html"
}
var err error
w, err = os.Create(presentOutput)
if err != nil {
fmt.Fprintf(os.Stderr, "present:%s", err)
command.SetExitStatus(3)
command.Exit()
}
}
err := RenderDoc(w, presentInput)
if err != nil {
fmt.Fprintf(os.Stderr, "present:%s", err)
command.SetExitStatus(3)
command.Exit()
}
return nil
}
var extensions = map[string]string{
".slide": "slides.tmpl",
".article": "article.tmpl",
}
var extensions_tmpl = map[string]string{
".slide": slides_tmpl,
".article": article_tmpl,
}
func isDoc(path string) bool {
_, ok := extensions[filepath.Ext(path)]
return ok
}
func VerifyDoc(docFile string) error {
doc, err := parse(docFile, 0)
if err != nil {
return err
}
dir := filepath.Dir(docFile)
return verify_doc(dir, doc)
}
// renderDoc reads the present file, builds its template representation,
// and executes the template, sending output to w.
func renderDoc(w io.Writer, base, docFile string) error {
// Read the input and build the doc structure.
doc, err := parse(docFile, 0)
if err != nil {
return err
}
// Find which template should be executed.
ext := filepath.Ext(docFile)
contentTmpl, ok := extensions[ext]
if !ok {
return fmt.Errorf("no template for extension %v", ext)
}
// Locate the template file.
actionTmpl := filepath.Join(base, "templates/action.tmpl")
contentTmpl = filepath.Join(base, "templates", contentTmpl)
// Read and parse the input.
tmpl := present.Template()
tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
if _, err := tmpl.ParseFiles(actionTmpl, contentTmpl); err != nil {
return err
}
// Execute the template.
return doc.Render(w, tmpl)
}
func RenderDoc(w io.Writer, docFile string) error {
// Read the input and build the doc structure.
doc, err := parse(docFile, 0)
if err != nil {
return err
}
// Find which template should be executed.
ext := filepath.Ext(docFile)
contentTmpl, ok := extensions_tmpl[ext]
if !ok {
return fmt.Errorf("no template for extension %v", ext)
}
// Locate the template file.
actionTmpl := action_tmpl //filepath.Join(base, "templates/action.tmpl")
// Read and parse the input.
tmpl := present.Template()
tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
if tmpl, err = tmpl.New("action").Parse(actionTmpl); err != nil {
return err
}
if tmpl, err = tmpl.New("content").Parse(contentTmpl); err != nil {
return err
}
// Execute the template.
return doc.Render(w, tmpl)
}
func parse(name string, mode present.ParseMode) (*present.Doc, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return present.Parse(f, name, 0)
}
func playable(c present.Code) bool {
return present.PlayEnabled && c.Play
}
func isSkipURL(url string) bool {
if filepath.HasPrefix(url, "http://") {
return true
}
if filepath.HasPrefix(url, "https://") {
return true
}
return false
}
func verify_path(root string, url string) error {
if isSkipURL(url) {
return nil
}
path := url
if !filepath.IsAbs(url) {
path = filepath.Join(root, path)
}
_, err := os.Stat(path)
if err != nil {
return err
}
return nil
}
func verify_doc(root string, doc *present.Doc) error {
for _, section := range doc.Sections {
for _, elem := range section.Elem {
switch i := elem.(type) {
case present.Image:
if err := verify_path(root, i.URL); err != nil {
return fmt.Errorf("! .image %s not exist", i.URL)
}
}
}
}
return nil
}
var action_tmpl = `
{/*
This is the action template.
It determines how the formatting actions are rendered.
*/}
{{define "section"}}
{{range .Lines}}{{.}}{{end}}
{{range $i, $l := .Lines}}{{if $i}}{{template "newline"}} {{end}}{{style $l}}{{end}}
{{end}} {{end}} {{define "code"}}