diff options
| author | clsr <clsr@clsr.net> | 2017-08-24 15:56:03 +0200 | 
|---|---|---|
| committer | clsr <clsr@clsr.net> | 2017-08-24 17:09:17 +0200 | 
| commit | 4184f047985bb28e79dd11863fe76c71865d89db (patch) | |
| tree | 14f6c6679c91ede15d1abaad9ef34aebe25a72e6 | |
| parent | 27a229a06f0354ee16bb97e6cf2dd1780923e74f (diff) | |
| download | cnm-go-4184f047985bb28e79dd11863fe76c71865d89db.tar.gz cnm-go-4184f047985bb28e79dd11863fe76c71865d89db.zip | |
Add ContainerBlock and RawTextContentsv0.2.0
Table.Rows() has been renamed to Table.Children().
RawBlock.Contents is now RawTextContents.
TextRawContents is now used for unknown text formats.
| -rw-r--r-- | content.go | 104 | ||||
| -rw-r--r-- | parse_test.go | 64 | ||||
| -rw-r--r-- | write_test.go | 2 | 
3 files changed, 118 insertions, 52 deletions
| @@ -18,9 +18,18 @@ type Block interface {  	// Args returns the block arguments.  	Args() []string +  	WriteIndent(w io.Writer, n int) error  } +// ContainerBlock represents a content block that contains only other blocks. +type ContainerBlock interface { +	Block + +	// Children returns the child blocks. +	Children() []Block +} +  // ContentBlock represents a block that holds other content blocks.  type ContentBlock struct {  	name     string @@ -190,8 +199,7 @@ func parseTextFormat(p *Parser, block *TokenBlock, format string) (TextContents,  	if parser := GetTextContentParser(format); parser != nil {  		return parser(p, block)  	} -	r, err := parseContentRaw(p, block) -	return TextPreContents{r.Contents}, err +	return parseTextRaw(p, block)  }  // TextContents represents the textual contents of a text block. @@ -327,13 +335,60 @@ func parseTextPre(p *Parser, block *TokenBlock) (TextContents, error) {  	return TextPreContents{strings.Join(lines, "\n")}, err  } +// TextRawContents represents raw (unesacped) contents of a text or raw block. +type TextRawContents struct { +	// Text is the raw content. +	Text string +} + +// WriteIndent writes the raw content indented by n tabs. +func (t TextRawContents) WriteIndent(w io.Writer, n int) error { +	ss := strings.Split(t.Text, "\n") +	for _, s := range ss { +		if err := writeIndent(w, s, n); err != nil { +			return err +		} +	} + +	return nil +} + +func parseTextRaw(p *Parser, block *TokenBlock) (TextContents, error) { +	var lines []string +	var ls []string +	var err error +	for err == nil { +		if !p.Empty() && p.Indent() <= block.Indent() { +			break +		} +		token := p.RawText() +		if text, ok := token.(*TokenRawText); ok { +			if len(ls) > 0 { +				lines = append(lines, ls...) +				ls = ls[:0] +			} +			lines = append(lines, text.Text) +		} else if _, ok := token.(*TokenEmptyLine); ok && len(lines) > 0 { +			ls = append(ls, "") +		} +		err = p.Next() +	} + +	return TextRawContents{strings.Join(lines, "\n")}, err +} +  // RawBlock represents a "raw" content block.  type RawBlock struct {  	// Syntax is the syntax of the block contents (first word of block argument)  	Syntax string  	// Contents is the raw content. -	Contents string +	Contents TextRawContents +} + +// NewRawBlock creates a new RawBlock. +func NewRawBlock(syntax, contents string) *RawBlock { +	return &RawBlock{syntax, TextRawContents{contents}}  }  // Name returns the block name "raw". @@ -356,14 +411,7 @@ func (r *RawBlock) WriteIndent(w io.Writer, n int) error {  	if err := writeIndent(w, s, n); err != nil {  		return err  	} -	if r.Contents != "" { -		ss := strings.Split(r.Contents, "\n") -		for _, s := range ss { -			if err := writeIndent(w, s, n+1); err != nil { -				return err -			} -		} -	} +	r.Contents.WriteIndent(w, n+1)  	return nil  } @@ -372,33 +420,16 @@ func parseContentRaw(p *Parser, block *TokenBlock) (*RawBlock, error) {  	if len(block.Args) > 0 {  		arg = block.Args[0]  	} -	rb := &RawBlock{arg, ""} +	rb := &RawBlock{arg, TextRawContents{}}  	if err := p.Next(); err != nil {  		return rb, err  	} -	var lines []string -	var ls []string -	var err error -	for err == nil { -		if !p.Empty() && p.Indent() <= block.Indent() { -			break -		} - -		token := p.RawText() -		if text, ok := token.(*TokenRawText); ok { -			if len(ls) > 0 { -				lines = append(lines, ls...) -				ls = ls[:0] -			} -			lines = append(lines, text.Text) -		} else if _, ok := token.(*TokenEmptyLine); ok && len(lines) > 0 { -			ls = append(ls, "") -		} -		err = p.Next() +	tc, err := parseTextRaw(p, block) +	if tc != nil { +		rb.Contents = tc.(TextRawContents)  	} -	rb.Contents = strings.Join(lines, "\n")  	return rb, err  } @@ -467,8 +498,8 @@ func (t *TableBlock) WriteIndent(w io.Writer, n int) error {  	return nil  } -// Rows returns the table's rows. -func (t *TableBlock) Rows() []Block { +// Children returns the table's rows. +func (t *TableBlock) Children() []Block {  	return t.rows  } @@ -560,6 +591,11 @@ type EmbedBlock struct {  	Description string  } +// NewEmbedBlock creates a new EmbedBlock. +func NewEmbedBlock(typ, url, desc string) *EmbedBlock { +	return &EmbedBlock{typ, url, desc} +} +  // Name returns the block name "embed".  func (e *EmbedBlock) Name() string { return "embed" } diff --git a/parse_test.go b/parse_test.go index 3fbf0f6..fc0ef87 100644 --- a/parse_test.go +++ b/parse_test.go @@ -125,6 +125,19 @@ var parseTests = map[string]*Document{  		},  	}, +	"content\n\ttext __nonexistent__\n\t\tqwe  zxc\n\n\t\tasd\\n123": &Document{ +		Content: &ContentBlock{ +			name: "content", +			args: nil, +			children: []Block{ +				&TextBlock{ +					Format:   "__nonexistent__", +					Contents: TextRawContents{"qwe  zxc\n\nasd\\n123"}, +				}, +			}, +		}, +	}, +  	"content\n\tnosuchblock\n\tsection test\n": &Document{  		Content: &ContentBlock{  			name: "content", @@ -360,7 +373,7 @@ content  						},  						&RawBlock{  							Syntax:   "text/plain", -							Contents: "of various \\n features", +							Contents: TextRawContents{"of various \\n features"},  						},  						&SectionBlock{ContentBlock{  							name: "section", @@ -462,7 +475,7 @@ func TestParse(t *testing.T) {  				t.Fatalf("ParseDocument(%q): error: %v", k, err)  			}  			if !documentEqual(d, v) { -				t.Fatalf("ParseDocument(%q):\nexpected:\n%#v\n     got:\n%#v", k, v, d) +				t.Fatalf("ParseDocument(%q):\nexpected:\n%#v\n     got:\n%#v\n\n%#v\n%#v", k, v, d, v.Content.Children()[0], d.Content.Children()[0])  			}  		})  	} @@ -591,15 +604,9 @@ func contentBlockEqual(a, b *ContentBlock) bool {  	if a.Name() != b.Name() {  		return false  	} -	aa, ba := a.Args(), b.Args() -	if len(aa) != len(ba) { +	if !argsEqual(a.Args(), b.Args()) {  		return false  	} -	for i := range aa { -		if aa[i] != ba[i] { -			return false -		} -	}  	ca, cb := a.Children(), b.Children()  	if len(ca) != len(cb) {  		return false @@ -612,12 +619,24 @@ func contentBlockEqual(a, b *ContentBlock) bool {  	return true  } +func argsEqual(a, b []string) bool { +	if len(a) != len(b) { +		return false +	} +	for i := range a { +		if a[i] != b[i] { +			return false +		} +	} +	return true +} +  func sectionBlockEqual(a, b *SectionBlock) bool { -	return contentBlockEqual(&a.ContentBlock, &b.ContentBlock) +	return a.Title() == b.Title() && contentBlockEqual(&a.ContentBlock, &b.ContentBlock)  }  func textBlockEqual(a, b *TextBlock) bool { -	if a.Format != b.Format { +	if !argsEqual(a.Args(), b.Args()) {  		return false  	}  	return textContentsEqual(a.Contents, b.Contents) @@ -639,7 +658,14 @@ func textContentsEqual(a, b TextContents) bool {  		}  		return textPreContentsEqual(va, vb) -	default: +	case TextRawContents: +		vb, ok := b.(TextRawContents) +		if !ok { +			return false +		} +		return textRawContentsEqual(va, vb) + +	default: // handle unknown contents, e.g. text fmt  		return reflect.TypeOf(a) == reflect.TypeOf(b) && reflect.DeepEqual(a, b)  	}  } @@ -660,16 +686,20 @@ func textPreContentsEqual(a, b TextPreContents) bool {  	return a == b  } +func textRawContentsEqual(a, b TextRawContents) bool { +	return a.Text == b.Text +} +  func rawBlockEqual(a, b *RawBlock) bool { -	return *a == *b +	return argsEqual(a.Args(), b.Args()) && textRawContentsEqual(a.Contents, b.Contents)  }  func listBlockEqual(a, b *ListBlock) bool { -	return contentBlockEqual(&a.ContentBlock, &b.ContentBlock) +	return a.Ordered() == b.Ordered() && contentBlockEqual(&a.ContentBlock, &b.ContentBlock)  }  func tableBlockEqual(a, b *TableBlock) bool { -	ra, rb := a.Rows(), b.Rows() +	ra, rb := a.Children(), b.Children()  	if len(ra) != len(rb) {  		return false  	} @@ -678,7 +708,7 @@ func tableBlockEqual(a, b *TableBlock) bool {  			return false  		}  	} -	return true +	return argsEqual(a.Args(), b.Args())  }  func rowBlockEqual(a, b *RowBlock) bool { @@ -690,5 +720,5 @@ func headerBlockEqual(a, b *HeaderBlock) bool {  }  func embedBlockEqual(a, b *EmbedBlock) bool { -	return *a == *b +	return argsEqual(a.Args(), b.Args())  } diff --git a/write_test.go b/write_test.go index fc13459..bf829a0 100644 --- a/write_test.go +++ b/write_test.go @@ -102,7 +102,7 @@ content  						},  						&RawBlock{  							Syntax:   "text/plain", -							Contents: "of various \\n features", +							Contents: TextRawContents{"of various \\n features"},  						},  						&SectionBlock{ContentBlock{  							name: "section", |