Better word wrapping #214

Merged
sloum merged 4 commits from raidancampbell/bombadillo:master into release-2.4.0 2022-02-16 04:03:48 +00:00
2 changed files with 20 additions and 17 deletions
Showing only changes of commit 070f7eb6ba - Show all commits

View File

@ -73,8 +73,7 @@ func (c *client) Draw() {
screen.WriteString("\033[0m")
screen.WriteString(c.TopBar.Render(c.Width, c.Options["theme"]))
screen.WriteString("\n")
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pageContent := c.PageState.Render(c.Height, c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pageContent := c.PageState.Render(c.Height, c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
Outdated
Review

In general I think ignoring error should be avoided where possible. I think we can likely encapsule this in a function that can be called wherever we need it:

func getMaxWidth() int {
    out, err := strconv.Atoi(c.Options["maxwidth"])
    if err != nil {
        out = 100
    }
    if out < 10 {
        out = 10
    }
    return out
}

It makes sense that we could really just store the value in a module var:

var MaxWidth = getMaxWidth()

Then in the code for setting config values have a case for changing maxwidth and reset the var. Then we can just reference the var everywhere instead of recasting to int in a few places (that said, I have not gotten to do a deep dive into your changes, just a cursory look.... so I may be overthinking this).

In general I think ignoring error should be avoided where possible. I think we can likely encapsule this in a function that can be called wherever we need it: ``` go func getMaxWidth() int { out, err := strconv.Atoi(c.Options["maxwidth"]) if err != nil { out = 100 } if out < 10 { out = 10 } return out } ```` It makes sense that we could really just store the value in a module var: ``` go var MaxWidth = getMaxWidth() ``` Then in the code for setting config values have a case for changing maxwidth and reset the var. Then we can just reference the var everywhere instead of recasting to int in a few places (that said, I have not gotten to do a deep dive into your changes, just a cursory look.... so I may be overthinking this).

070f7eb6ba261866395706f709d12dff3ead2e74 contains a first pass on this. Since c.Options is both a field on the struct and altered by reading in the configuration after instantiating the struct, it's a bit less clean.

Other potential options:

  • add a piece of state to hold a sync.Once (existed in 1.12) in getMaxWidth to avoid the checks and casts
  • have some hook on the client that gets called after the configuration file is read in
  • see if the configuration can be read in first, then passed to the client constructor, then maxWidth can be a field on the client alongside Width
`070f7eb6ba261866395706f709d12dff3ead2e74` contains a first pass on this. Since `c.Options` is both a field on the struct and altered by reading in the configuration after instantiating the struct, it's a bit less clean. Other potential options: - add a piece of state to hold a `sync.Once` (existed in 1.12) in `getMaxWidth` to avoid the checks and casts - have some hook on the client that gets called after the configuration file is read in - see if the configuration can be read in first, then passed to the client constructor, then `maxWidth` can be a field on the client alongside `Width`
var re *regexp.Regexp
if c.Options["theme"] == "inverse" {
screen.WriteString("\033[7m")
@ -259,8 +258,7 @@ func (c *client) TakeControlInput() {
}
err = c.NextSearchItem(0)
if err != nil {
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
c.PageState.History[c.PageState.Position].WrapContent(c.Width-1,maxWidth,(c.Options["theme"] == "color"))
c.PageState.History[c.PageState.Position].WrapContent(c.Width-1,getMaxWidth(c.Options),(c.Options["theme"] == "color"))
c.Draw()
}
case ':', ' ':
@ -990,8 +988,7 @@ func (c *client) handleGopher(u Url) {
} else {
pg.FileType = "text"
}
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pg.WrapContent(c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pg.WrapContent(c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1018,8 +1015,7 @@ func (c *client) handleGemini(u Url) {
u.Mime = capsule.MimeMin
pg := MakePage(u, capsule.Content, capsule.Links)
pg.FileType = capsule.MimeMaj
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pg.WrapContent(c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pg.WrapContent(c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1085,8 +1081,7 @@ func (c *client) handleLocal(u Url) {
if ext == ".jpg" || ext == ".jpeg" || ext == ".gif" || ext == ".png" {
pg.FileType = "image"
}
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pg.WrapContent(c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pg.WrapContent(c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1102,8 +1097,7 @@ func (c *client) handleFinger(u Url) {
return
}
pg := MakePage(u, content, []string{})
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pg.WrapContent(c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pg.WrapContent(c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1123,8 +1117,7 @@ func (c *client) handleWeb(u Url) {
return
}
pg := MakePage(u, page.Content, page.Links)
maxWidth, _ := strconv.Atoi(c.Options["maxwidth"])
pg.WrapContent(c.Width-1, maxWidth, (c.Options["theme"] == "color"))
pg.WrapContent(c.Width-1, getMaxWidth(c.Options), (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1265,3 +1258,16 @@ func updateTimeouts(timeoutString string) error {
return nil
}
// getMaxWidth looks through the given options map and will safely return a max width to render
// if the option is missing or malformed, it will default to 100. A sane minimum of 10 is enforced.
func getMaxWidth(options map[string]string) int {
out, err := strconv.Atoi(options["maxwidth"])
if err != nil {
out = 100
}
if out < 10 {
out = 10
}
return out
}

View File

@ -70,9 +70,6 @@ func (p *Page) WrapContent(width, maxWidth int, color bool) {
p.RenderImage(width)
return
}
if maxWidth < 100 {
maxWidth = 100
}
width = min(width, maxWidth)
counter := 0
Outdated
Review

I'm not sure I follow why this is here. Since we are trying to wrap at maxwidth and remove hardcoded values in favor of the passed value that comes from the config, why are we hardcoding 100 here?

I'm not sure I follow why this is here. Since we are trying to wrap at maxwidth and remove hardcoded values in favor of the passed value that comes from the config, why are we hardcoding 100 here?

The intent here was to catch malformed / missing configuration entries: your suggestion of wrapping the logic into a getMaxWidth function will solve this problem and remove the need here.

Much better, thanks!

The intent here was to catch malformed / missing configuration entries: your suggestion of wrapping the logic into a `getMaxWidth` function will solve this problem and remove the need here. Much better, thanks!
spacer := ""