Browse Source

Added width restriction mechanism

Benton Edmondson 2 years ago
parent
commit
a9405e6171

+ 1 - 1
gemtext/gemtext.go

@@ -15,7 +15,7 @@ import (
 // e.g. block quotes should probably be able to start
 // with tabs
 
-func Render(text string) (string, error) {
+func Render(text string, width int) (string, error) {
 	lines := strings.Split(text, "\n")
 	result := ""
 	preformattedMode := false

+ 1 - 1
gemtext/gemtext_test.go

@@ -20,7 +20,7 @@ func TestBasic(t *testing.T) {
 =>http://example.org/
 
 ` + "```\ncode block\nhere\n```"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}

+ 3 - 0
go.mod

@@ -3,6 +3,9 @@ module mimicry
 go 1.19
 
 require (
+	github.com/mattn/go-runewidth v0.0.12 // indirect
+	github.com/muesli/reflow v0.3.0 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/yuin/goldmark v1.5.4 // indirect
 	golang.org/x/net v0.5.0 // indirect
 )

+ 7 - 0
go.sum

@@ -1,3 +1,10 @@
+github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
 github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=

+ 1 - 1
hypertext/hypertext.go

@@ -11,7 +11,7 @@ import (
 
 /* Terminal codes and control characters should already be escaped
    by this point */
-func Render(text string) (string, error) {
+func Render(text string, width int) (string, error) {
 	nodes, err := html.ParseFragment(strings.NewReader(text), &html.Node{
 		Type: html.ElementNode,
 		Data: "body",

+ 9 - 9
hypertext/hypertext_test.go

@@ -34,7 +34,7 @@ func TestMergeText(t *testing.T) {
 
 func TestStyles(t *testing.T) {
 	input := "<s>s</s><code>code</code><i>i</i><u>u</u><mark>mark</mark>"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
@@ -49,7 +49,7 @@ func TestStyles(t *testing.T) {
 
 func TestSurroundingBlocks(t *testing.T) {
 	input := "<p>first</p>in \t<mark>the</mark> \rmiddle<p>last</p>"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
@@ -63,7 +63,7 @@ last`
 
 func TestAdjacentBlocks(t *testing.T) {
 	input := "\t<p>first</p>\n\t<p>second</p>"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
@@ -75,7 +75,7 @@ second`
 
 func TestPoetry(t *testing.T) {
 	input := "he shouted\t\ta few words<br>at those annoying birds<br><br>and that they heard"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
@@ -89,7 +89,7 @@ and that they heard`
 
 func TestPreservation(t *testing.T) {
 	input := "<pre>tab\tand multi-space   \n\n\n\n\n far down</pre>"
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
@@ -108,7 +108,7 @@ func TestNestedBlocks(t *testing.T) {
 <p> </p>
 
 <p><img src="https://i.snap.as/P8qpdMbM.jpg" alt=""/></p>`
-	output, err := Render(input)	
+	output, err := Render(input, 50)	
 	if err != nil {
 		panic(err)
 	}
@@ -120,7 +120,7 @@ func TestNestedBlocks(t *testing.T) {
 
 func TestAdjacentLists(t *testing.T) {
 	input := `<ul><li>top list</li></ul><ul><li>bottom list</li></ul>`
-	output, err := Render(input)	
+	output, err := Render(input, 50)	
 	if err != nil {
 		panic(err)
 	}
@@ -131,7 +131,7 @@ func TestAdjacentLists(t *testing.T) {
 
 func TestNestedLists(t *testing.T) {
 	input := `<ul><li>top list<ul><li>nested</li></ul></li></ul>`
-	output, err := Render(input)	
+	output, err := Render(input, 50)	
 	if err != nil {
 		panic(err)
 	}
@@ -142,7 +142,7 @@ func TestNestedLists(t *testing.T) {
 
 func TestBlockInList(t *testing.T) {
 	input := `<ul><li>top list<p><ul><li>paragraph</li></ul></p></li></ul>`
-	output, err := Render(input)	
+	output, err := Render(input, 50)	
 	if err != nil {
 		panic(err)
 	}

+ 1 - 1
kinds/actor.go

@@ -54,7 +54,7 @@ func (a Actor) Bio() (string, error) {
 	if err != nil {
 		mediaType = "text/html"
 	}
-	return render.Render(body, mediaType)
+	return render.Render(body, mediaType, 80)
 }
 
 func (a Actor) String() (string, error) {

+ 1 - 1
kinds/post.go

@@ -32,7 +32,7 @@ func (p Post) Body() (string, error) {
 	if err != nil {
 		mediaType = "text/html"
 	}
-	return render.Render(body, mediaType)
+	return render.Render(body, mediaType, 80)
 }
 
 func (p Post) BodyPreview() (string, error) {

+ 2 - 2
markdown/markdown.go

@@ -10,13 +10,13 @@ import (
 
 var renderer = goldmark.New(goldmark.WithExtensions(extension.GFM))
 
-func Render(text string) (string, error) {
+func Render(text string, width int) (string, error) {
 	var buf bytes.Buffer
 	if err := renderer.Convert([]byte(text), &buf); err != nil {
 		return "", nil
 	}
 	output := buf.String()
-	rendered, err := hypertext.Render(output)
+	rendered, err := hypertext.Render(output, width)
 	if err != nil {
 		return "", err
 	}

+ 1 - 1
markdown/markdown_test.go

@@ -13,7 +13,7 @@ func TestBasic(t *testing.T) {
 
 * Nested list
   * Nesting`
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}

+ 4 - 2
plaintext/plaintext.go

@@ -4,9 +4,10 @@ import (
 	"regexp"
 	"mimicry/style"
 	"strings"
+	"mimicry/util"
 )
 
-func Render(text string) (string, error) {
+func Render(text string, width int) (string, error) {
 	/*
 		Oversimplistic URL regexp based on RFC 3986, Appendix A
 		It matches:
@@ -19,5 +20,6 @@ func Render(text string) (string, error) {
 
 	url := regexp.MustCompile(`[A-Za-z][A-Za-z0-9+\-.]*://[A-Za-z0-9.?#/@:%_~!$&'()*+,;=\[\]\-]+`)
 	rendered := url.ReplaceAllStringFunc(text, style.Link)
-	return strings.TrimSpace(rendered), nil
+	wrapped := util.Wrap(rendered, width)
+	return strings.TrimSpace(wrapped), nil
 }

+ 6 - 8
plaintext/plaintext_test.go

@@ -10,20 +10,18 @@ func TestBasic(t *testing.T) {
 	input := `Yes, Jim, I found it under "http://www.w3.org/Addressing/",
 but you can probably pick it up from <ftp://foo.example.com/rfc/>.
 Note the warning in <http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING>.`
-	output, err := Render(input)
+	output, err := Render(input, 50)
 	if err != nil {
 		panic(err)
 	}
 
-	expected := `Yes, Jim, I found it under "` +
+	expected := "Yes, Jim, I found it under\n\"" +
 		style.Link("http://www.w3.org/Addressing/") +
-		`",
-but you can probably pick it up from <` +
+		"\",\nbut you can probably pick it up from\n<" +
 		style.Link("ftp://foo.example.com/rfc/") +
-		`>.
-Note the warning in <` +
-		style.Link("http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING") +
-		`>.`
+		">.\nNote the warning in\n<" +
+		style.Link("http://www.ics.uci.edu/pub/ietf/uri/historical.ht\nml#WARNING") +
+		">."
 
 	util.AssertEqual(expected, output, t)
 }

+ 7 - 5
render/render.go

@@ -10,19 +10,21 @@ import (
 	"unicode"
 )
 
+// TODO: perhaps `dropControlCharacters` should happen to all
+//	`getNatural` strings when they are pulled from the JSON
 // TODO: need to add a width parameter to all of this
-func Render(text string, mediaType string) (string, error) {
+func Render(text string, mediaType string, width int) (string, error) {
 	text = strings.Map(dropControlCharacters, text)
 
 	switch {
 	case mediaType == "text/plain": 
-		return plaintext.Render(text)
+		return plaintext.Render(text, width)
 	case mediaType == "text/html":
-		return hypertext.Render(text)
+		return hypertext.Render(text, width)
 	case mediaType == "text/gemini":
-		return gemtext.Render(text)
+		return gemtext.Render(text, width)
 	case mediaType == "text/markdown":
-		return markdown.Render(text)
+		return markdown.Render(text, width)
 	default:
 		return "", errors.New("Cannot render text of mime type " + mediaType)
 	}

+ 2 - 2
render/render_test.go

@@ -8,12 +8,12 @@ import (
 
 func TestControlCharacterEscapes(t *testing.T) {
 	input := "Yes, \u0000Jim, I\nfound it\tunder \u001Bhttp://www.w3.org/Addressing/"
-	output, err := Render(input, "text/plain")
+	output, err := Render(input, "text/plain", 50)
 	if err != nil {
 		panic(err)
 	}
 
-	expected := "Yes, Jim, I\nfound it\tunder " +
+	expected := "Yes, Jim, I\nfound it    under " +
 		style.Link("http://www.w3.org/Addressing/")
 
 	util.AssertEqual(expected, output, t)

+ 9 - 0
util/util.go

@@ -2,10 +2,19 @@ package util
 
 import (
 	"testing"
+	"github.com/muesli/reflow/wordwrap"
+	"github.com/muesli/reflow/wrap"
 )
 
 func AssertEqual(expected string, output string, t *testing.T) {
 	if expected != output {
 		t.Fatalf("Expected `%s` not `%s`\n", expected, output)
 	}
+}
+
+func Wrap(text string, width int) string {
+	if width < 1 {
+		width = 1
+	}
+	return wrap.String(wordwrap.String(text, width), width)
 }