Support open "current content page" in browser

This commit adds a new `--navigateToChanged` and config setting with the same name, that, when running the Hugo server with live reload enabled, will navigate to the current content file's URL on save. 

This is really useful for site-wide content changes (copyedits etc.).
Fixes #3643
This commit is contained in:
Bjørn Erik Pedersen 2017-06-26 21:34:16 +02:00 committed by GitHub
parent 7198ea8a1e
commit c825a73121
5 changed files with 114 additions and 6 deletions

View file

@ -981,10 +981,30 @@ func (c *commandeer) newWatcher(port int) error {
} }
if !buildWatch && !c.Cfg.GetBool("disableLiveReload") { if !buildWatch && !c.Cfg.GetBool("disableLiveReload") {
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
navigate := c.Cfg.GetBool("navigateToChanged")
var p *hugolib.Page
if navigate {
// It is probably more confusing than useful
// to navigate to a new URL on RENAME etc.
// so for now we use the WRITE event only.
name := pickOneWritePath(dynamicEvents)
if name != "" {
p = Hugo.GetContentPage(name)
}
}
if p != nil {
livereload.NavigateToPath(p.RelPermalink())
} else {
livereload.ForceRefresh() livereload.ForceRefresh()
} }
} }
}
case err := <-watcher.Errors: case err := <-watcher.Errors:
if err != nil { if err != nil {
c.Logger.ERROR.Println(err) c.Logger.ERROR.Println(err)
@ -1007,6 +1027,16 @@ func (c *commandeer) newWatcher(port int) error {
return nil return nil
} }
func pickOneWritePath(events []fsnotify.Event) string {
for _, ev := range events {
if ev.Op&fsnotify.Write == fsnotify.Write {
return ev.Name
}
}
return ""
}
func (c *commandeer) isStatic(path string) bool { func (c *commandeer) isStatic(path string) bool {
return strings.HasPrefix(path, c.PathSpec().GetStaticDirPath()) || (len(c.PathSpec().GetThemesDirPath()) > 0 && strings.HasPrefix(path, c.PathSpec().GetThemesDirPath())) return strings.HasPrefix(path, c.PathSpec().GetStaticDirPath()) || (len(c.PathSpec().GetThemesDirPath()) > 0 && strings.HasPrefix(path, c.PathSpec().GetThemesDirPath()))
} }

View file

@ -33,6 +33,7 @@ import (
var ( var (
disableLiveReload bool disableLiveReload bool
navigateToChanged bool
renderToDisk bool renderToDisk bool
serverAppend bool serverAppend bool
serverInterface string serverInterface string
@ -87,6 +88,7 @@ func init() {
serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed") serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL") serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild") serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)") serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
serverCmd.Flags().String("memstats", "", "log memory usage to this file") serverCmd.Flags().String("memstats", "", "log memory usage to this file")
serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".") serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")
@ -110,6 +112,10 @@ func server(cmd *cobra.Command, args []string) error {
c.Set("disableLiveReload", disableLiveReload) c.Set("disableLiveReload", disableLiveReload)
} }
if cmd.Flags().Changed("navigateToChanged") {
c.Set("navigateToChanged", navigateToChanged)
}
if serverWatch { if serverWatch {
c.Set("watch", true) c.Set("watch", true)
} }

View file

@ -19,6 +19,8 @@ import (
"strings" "strings"
"sync" "sync"
"path/filepath"
"github.com/gohugoio/hugo/deps" "github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/helpers"
@ -38,6 +40,27 @@ type HugoSites struct {
*deps.Deps *deps.Deps
} }
// GetContentPage finds a Page with content given the absolute filename.
// Returns nil if none found.
func (h *HugoSites) GetContentPage(filename string) *Page {
s := h.Sites[0]
contendDir := filepath.Join(s.PathSpec.AbsPathify(s.Cfg.GetString("contentDir")))
if !strings.HasPrefix(filename, contendDir) {
return nil
}
rel := strings.TrimPrefix(filename, contendDir)
rel = strings.TrimPrefix(rel, helpers.FilePathSeparator)
pos := s.rawAllPages.findPagePosByFilePath(rel)
if pos == -1 {
return nil
}
return s.rawAllPages[pos]
}
// NewHugoSites creates a new collection of sites given the input sites, building // NewHugoSites creates a new collection of sites given the input sites, building
// a language configuration based on those. // a language configuration based on those.
func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) { func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {

View file

@ -223,6 +223,12 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
require.NotNil(t, s.disabledKinds) require.NotNil(t, s.disabledKinds)
} }
gp1 := sites.GetContentPage(filepath.FromSlash("content/sect/doc1.en.md"))
require.NotNil(t, gp1)
require.Equal(t, "doc1", gp1.Title)
gp2 := sites.GetContentPage(filepath.FromSlash("content/sect/notfound.md"))
require.Nil(t, gp2)
enSite := sites.Sites[0] enSite := sites.Sites[0]
enSiteHome := enSite.getPage(KindHome) enSiteHome := enSite.getPage(KindHome)
require.True(t, enSiteHome.IsTranslated()) require.True(t, enSiteHome.IsTranslated())

File diff suppressed because one or more lines are too long