123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package main
- import (
- "fmt"
- "html/template"
- "io/ioutil"
- "log"
- "net"
- "net/http"
- "os"
- "path/filepath"
- "strings"
- "github.com/codegangsta/cli"
- "github.com/jaschaephraim/lrserver"
- "github.com/russross/blackfriday"
- "github.com/skratchdot/open-golang/open"
- "gopkg.in/fsnotify.v1"
- )
- var watchDir = "."
- // template with list of files found in watchDir (with livereload)
- var mdList = template.Must(template.New("mdList").Parse(`<!doctype html>
- <html>
- <head>
- <title>List of Markdown files</title>
- <script src="http://localhost:35729/livereload.js"></script>
- <body>
- <ul>
- {{range .}}
- <li><a href="/md?file={{.}}">{{.}}</a></li>
- {{end}}
- </ul>
- </body>
- </html>`))
- // template for rendering markdown content (with livereload)
- var md = template.Must(template.New("md").Parse(`<!doctype html>
- <html>
- <head>
- <!-- <link href="http://kevinburke.bitbucket.org/markdowncss/markdown.css" rel="stylesheet"></link>-->
- <script src="http://localhost:35729/livereload.js"></script>
- <body>
- {{.}}
- </body>
- </html>`))
- func main() {
- app := cli.NewApp()
- app.Name = "livefriday"
- app.Usage = "see your markdown grow as you save it"
- app.Flags = []cli.Flag{
- cli.StringFlag{Name: "dir,d", Value: ".", Usage: "The directory to watch and compile"},
- cli.StringFlag{Name: "host", Value: "localhost", Usage: "The http host to listen on"},
- cli.IntFlag{Name: "port,p", Value: 0, Usage: "The http port to listen on"},
- }
- app.Action = run
- app.Run(os.Args)
- }
- func run(c *cli.Context) {
- // Create file watcher
- watcher, err := fsnotify.NewWatcher()
- check(err)
- defer watcher.Close()
- watchDir = c.String("dir")
- // Add dir to watcher
- err = watcher.Add(watchDir)
- check(err)
- // Start LiveReload server
- lr := lrserver.New(lrserver.DefaultName, lrserver.DefaultPort)
- go func() {
- check(lr.ListenAndServe())
- }()
- // Start goroutine that requests reload upon watcher event
- go func() {
- for {
- event := <-watcher.Events
- if strings.HasSuffix(event.Name, ".md") || strings.HasSuffix(event.Name, ".mdown") {
- lr.Reload(event.Name)
- }
- }
- }()
- // Start serving html
- http.HandleFunc("/", indexHandler)
- http.HandleFunc("/md", mdHandler)
- http.Handle("/assets/", http.StripPrefix("/assets", http.FileServer(http.Dir(watchDir))))
- listenAddr := fmt.Sprintf("%s:%d", c.String("host"), c.Int("port"))
- // Start listening first.
- listener, err := net.Listen("tcp", listenAddr)
- check(err)
- listenAddr = listener.Addr().String()
- // Open a browser tab and navigate to the main page.
- go open.Run("http://" + listenAddr)
- log.Println("livefriday server is running at http://" + listenAddr)
- err = http.Serve(listener, nil)
- check(err)
- }
- // indexHandler builds a list with links to all .md files in the watchDir
- func indexHandler(rw http.ResponseWriter, req *http.Request) {
- dir, err := os.Open(watchDir)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
- dirNames, err := dir.Readdirnames(-1)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
- mdFiles := make([]string, len(dirNames))
- i := 0
- for _, n := range dirNames {
- if strings.HasSuffix(n, ".md") || strings.HasSuffix(n, ".mdown") {
- mdFiles[i] = n
- i++
- }
- }
- rw.WriteHeader(http.StatusOK)
- mdList.Execute(rw, mdFiles[:i])
- }
- // mdHandler ReadFile's the passed file argument and puts it through blackfriday
- func mdHandler(rw http.ResponseWriter, req *http.Request) {
- fname := req.URL.Query().Get("file")
- if fname == "" {
- http.Error(rw, "no fname", http.StatusBadRequest)
- return
- }
- input, err := ioutil.ReadFile(filepath.Join(watchDir, filepath.Base(fname)))
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
- rw.WriteHeader(http.StatusOK)
- md.Execute(rw, template.HTML(blackfriday.MarkdownCommon(input)))
- }
- func check(err error) {
- if err != nil {
- log.Fatalln(err)
- }
- }
|