Skip to content

Commit c825a73

Browse files
authored
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
1 parent 7198ea8 commit c825a73

File tree

5 files changed

+114
-6
lines changed

5 files changed

+114
-6
lines changed

‎commands/hugo.go‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,28 @@ func (c *commandeer) newWatcher(port int) error {
981981
}
982982

983983
if !buildWatch && !c.Cfg.GetBool("disableLiveReload") {
984-
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
985-
livereload.ForceRefresh()
984+
985+
navigate := c.Cfg.GetBool("navigateToChanged")
986+
987+
var p *hugolib.Page
988+
989+
if navigate {
990+
991+
// It is probably more confusing than useful
992+
// to navigate to a new URL on RENAME etc.
993+
// so for now we use the WRITE event only.
994+
name := pickOneWritePath(dynamicEvents)
995+
996+
if name != "" {
997+
p = Hugo.GetContentPage(name)
998+
}
999+
}
1000+
1001+
if p != nil {
1002+
livereload.NavigateToPath(p.RelPermalink())
1003+
} else {
1004+
livereload.ForceRefresh()
1005+
}
9861006
}
9871007
}
9881008
case err := <-watcher.Errors:
@@ -1007,6 +1027,16 @@ func (c *commandeer) newWatcher(port int) error {
10071027
return nil
10081028
}
10091029

1030+
func pickOneWritePath(events []fsnotify.Event) string {
1031+
for _, ev := range events {
1032+
if ev.Op&fsnotify.Write == fsnotify.Write {
1033+
return ev.Name
1034+
}
1035+
}
1036+
1037+
return ""
1038+
}
1039+
10101040
func (c *commandeer) isStatic(path string) bool {
10111041
return strings.HasPrefix(path, c.PathSpec().GetStaticDirPath()) || (len(c.PathSpec().GetThemesDirPath()) > 0 && strings.HasPrefix(path, c.PathSpec().GetThemesDirPath()))
10121042
}

‎commands/server.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333

3434
var (
3535
disableLiveReload bool
36+
navigateToChanged bool
3637
renderToDisk bool
3738
serverAppend bool
3839
serverInterface string
@@ -87,6 +88,7 @@ func init() {
8788
serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
8889
serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
8990
serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
91+
serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
9092
serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
9193
serverCmd.Flags().String("memstats", "", "log memory usage to this file")
9294
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 {
110112
c.Set("disableLiveReload", disableLiveReload)
111113
}
112114

115+
if cmd.Flags().Changed("navigateToChanged") {
116+
c.Set("navigateToChanged", navigateToChanged)
117+
}
118+
113119
if serverWatch {
114120
c.Set("watch", true)
115121
}

‎hugolib/hugo_sites.go‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"strings"
2020
"sync"
2121

22+
"path/filepath"
23+
2224
"github.com/gohugoio/hugo/deps"
2325
"github.com/gohugoio/hugo/helpers"
2426

@@ -38,6 +40,27 @@ type HugoSites struct {
3840
*deps.Deps
3941
}
4042

43+
// GetContentPage finds a Page with content given the absolute filename.
44+
// Returns nil if none found.
45+
func (h *HugoSites) GetContentPage(filename string) *Page {
46+
s := h.Sites[0]
47+
contendDir := filepath.Join(s.PathSpec.AbsPathify(s.Cfg.GetString("contentDir")))
48+
if !strings.HasPrefix(filename, contendDir) {
49+
return nil
50+
}
51+
52+
rel := strings.TrimPrefix(filename, contendDir)
53+
rel = strings.TrimPrefix(rel, helpers.FilePathSeparator)
54+
55+
pos := s.rawAllPages.findPagePosByFilePath(rel)
56+
57+
if pos == -1 {
58+
return nil
59+
}
60+
return s.rawAllPages[pos]
61+
62+
}
63+
4164
// NewHugoSites creates a new collection of sites given the input sites, building
4265
// a language configuration based on those.
4366
func newHugoSites(cfg deps.DepsCfg, sites ...*Site) (*HugoSites, error) {

‎hugolib/hugo_sites_build_test.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) {
223223
require.NotNil(t, s.disabledKinds)
224224
}
225225

226+
gp1 := sites.GetContentPage(filepath.FromSlash("content/sect/doc1.en.md"))
227+
require.NotNil(t, gp1)
228+
require.Equal(t, "doc1", gp1.Title)
229+
gp2 := sites.GetContentPage(filepath.FromSlash("content/sect/notfound.md"))
230+
require.Nil(t, gp2)
231+
226232
enSite := sites.Sites[0]
227233
enSiteHome := enSite.getPage(KindHome)
228234
require.True(t, enSiteHome.IsTranslated())

0 commit comments

Comments
 (0)