diff --git a/pkg/document/block.go b/pkg/document/block.go index 4dea384ee..bea7d5bab 100644 --- a/pkg/document/block.go +++ b/pkg/document/block.go @@ -3,6 +3,7 @@ package document import ( "bytes" "encoding/json" + "errors" "math" "regexp" "strconv" @@ -47,7 +48,8 @@ type CodeBlockEncoding int const ( Fenced CodeBlockEncoding = iota + 1 UnfencedWithSpaces - UnfencedWithTab + // todo(sebastian): goldmark converts all tabs to spaces + // UnfencedWithTab ) type CodeBlock struct { @@ -69,23 +71,37 @@ var _ Block = (*CodeBlock)(nil) func newCodeBlock( document *Document, - node *ast.FencedCodeBlock, + node ast.Node, identityResolver identityResolver, nameResolver *nameResolver, source []byte, - encoding CodeBlockEncoding, render renderer, ) (*CodeBlock, error) { - attributes, err := getAttributes(node, source, DefaultAttributeParser) + var fenced *ast.FencedCodeBlock + encoding := Fenced + + switch node.Kind() { + case ast.KindCodeBlock: + // todo(sebastian): should we attempt to preserve tab vs spaces? + encoding = UnfencedWithSpaces + fenced = ast.NewFencedCodeBlock(ast.NewText()) + fenced.BaseBlock = node.(*ast.CodeBlock).BaseBlock + case ast.KindFencedCodeBlock: + fenced = node.(*ast.FencedCodeBlock) + default: + return nil, errors.New("invalid node kind neither CodeBlock nor FencedCodeBlock") + } + + attributes, err := getAttributes(fenced, source, DefaultAttributeParser) if err != nil { return nil, err } - id, hasID := identityResolver.GetCellID(node, attributes) + id, hasID := identityResolver.GetCellID(fenced, attributes) - name, hasName := getName(node, source, nameResolver, attributes) + name, hasName := getName(fenced, source, nameResolver, attributes) - value, err := render(node, source) + value, err := render(fenced, source) if err != nil { return nil, err } @@ -96,16 +112,18 @@ func newCodeBlock( encoding: encoding, id: id, idGenerated: !hasID, - inner: node, - intro: getIntro(node, source), - language: getLanguage(node, source), - lines: getLines(node, source), + inner: fenced, + intro: getIntro(fenced, source), + language: getLanguage(fenced, source), + lines: getLines(fenced, source), name: name, nameGenerated: !hasName, value: value, }, nil } +func (b *CodeBlock) FencedEncoding() bool { return b.encoding == Fenced } + func (b *CodeBlock) Attributes() map[string]string { return b.attributes } func (b *CodeBlock) Background() bool { diff --git a/pkg/document/document.go b/pkg/document/document.go index 08ba4bef6..8f793cc84 100644 --- a/pkg/document/document.go +++ b/pkg/document/document.go @@ -3,7 +3,6 @@ package document import ( "bytes" "fmt" - "strconv" "sync" "github.com/pkg/errors" @@ -171,26 +170,16 @@ func (d *Document) parse() { func (d *Document) buildBlocksTree(parent ast.Node, node *Node) error { for astNode := parent.FirstChild(); astNode != nil; astNode = astNode.NextSibling() { - codeBlockEncoding := Fenced switch astNode.Kind() { - case ast.KindCodeBlock: - b := ast.NewFencedCodeBlock(ast.NewText()) - b.BaseBlock = astNode.(*ast.CodeBlock).BaseBlock - astNode = b - - codeBlockEncoding = UnfencedWithSpaces - fallthrough - case ast.KindFencedCodeBlock: + case ast.KindCodeBlock, ast.KindFencedCodeBlock: block, err := newCodeBlock( d, - astNode.(*ast.FencedCodeBlock), + astNode, d.identityResolver, d.nameResolver, d.content, - codeBlockEncoding, d.renderer, ) - block.attributes["runme.dev/fenced"] = strconv.FormatBool(codeBlockEncoding == Fenced) if err != nil { return errors.WithStack(err) } diff --git a/pkg/document/editor/cell.go b/pkg/document/editor/cell.go index 29b509b5e..5e482054e 100644 --- a/pkg/document/editor/cell.go +++ b/pkg/document/editor/cell.go @@ -175,6 +175,10 @@ func toCellsRec( } metadata[PrefixAttributeName(InternalAttributePrefix, "nameGenerated")] = nameGeneratedStr + if !block.FencedEncoding() { + metadata[PrefixAttributeName(InternalAttributePrefix, "fenced")] = "false" + } + *cells = append(*cells, &Cell{ Kind: CodeKind, Value: string(block.Content()), @@ -322,7 +326,15 @@ func serializeCellCodeBlock(w io.Writer, cell *Cell) { var buf bytes.Buffer value := cell.Value - if b, _ := strconv.ParseBool(cell.Metadata[PrefixAttributeName(InternalAttributePrefix, "fenced")]); b { + if b, err := strconv.ParseBool(cell.Metadata[PrefixAttributeName(InternalAttributePrefix, "fenced")]); err == nil && !b { + for _, v := range strings.Split(value, "\n") { + _, _ = buf.Write(bytes.Repeat([]byte{' '}, 4)) + _, _ = buf.WriteString(v) + _ = buf.WriteByte('\n') + } + + serializeCellOutputsText(&buf, cell) + } else { ticksCount := longestBacktickSeq(value) if ticksCount < 3 { ticksCount = 3 @@ -340,14 +352,6 @@ func serializeCellCodeBlock(w io.Writer, cell *Cell) { serializeCellOutputsText(&buf, cell) _, _ = buf.Write(bytes.Repeat([]byte{'`'}, ticksCount)) - } else { - for _, v := range strings.Split(value, "\n") { - _, _ = buf.Write(bytes.Repeat([]byte{' '}, 4)) - _, _ = buf.WriteString(v) - _ = buf.WriteByte('\n') - } - - serializeCellOutputsText(&buf, cell) } serializeCellOutputsImage(&buf, cell)