Skip to content

Commit

Permalink
Make cell names more obvious in markdown viewers (#738)
Browse files Browse the repository at this point in the history
Cells with names will contain a leading comment with the name of the
cell. This is helpful if you are new to Runme. Let's start with `dagger
shell` first because call names are used to string together
functions/pipelines.
  • Loading branch information
sourishkrout authored Feb 10, 2025
1 parent d4b29a7 commit 828abc8
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 18 deletions.
13 changes: 12 additions & 1 deletion pkg/document/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,19 @@ func (b *CodeBlock) Tags() []string {
return superset
}

func (b *CodeBlock) valueWithoutLabelComments() []byte {
var lines [][]byte
for _, line := range bytes.Split(b.value, []byte{'\n'}) {
if bytes.HasPrefix(line, []byte("### ")) {
continue
}
lines = append(lines, line)
}
return bytes.Join(lines, []byte{'\n'})
}

func (b *CodeBlock) Content() []byte {
value := bytes.Trim(b.value, "\n")
value := bytes.Trim(b.valueWithoutLabelComments(), "\n")
lines := bytes.Split(value, []byte{'\n'})
if len(lines) < 2 {
return b.value
Expand Down
21 changes: 17 additions & 4 deletions pkg/document/editor/cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
InternalAttributePrefix = "runme.dev"
PrivateAttributePrefix = "_"
defaultAttributeFormat = "json"
labelCommentPreamble = "### Exported in runme.dev as "
)

type CellKind int
Expand Down Expand Up @@ -335,13 +336,13 @@ func removeAnsiCodes(str string) string {
return re.ReplaceAllString(str, "")
}

func serializeCells(cells []*Cell) ([]byte, error) {
func serializeCells(cells []*Cell, labelComment bool) ([]byte, error) {
var buf bytes.Buffer

for idx, cell := range cells {
switch cell.Kind {
case CodeKind:
err := serializeCellCodeBlock(&buf, cell)
err := serializeCellCodeBlock(&buf, cell, labelComment)
if err != nil {
return nil, err
}
Expand All @@ -363,13 +364,22 @@ func serializeCells(cells []*Cell) ([]byte, error) {
return buf.Bytes(), nil
}

func serializeCellCodeBlock(w io.Writer, cell *Cell) error {
func serializeCellCodeBlock(w io.Writer, cell *Cell, labelComment bool) error {
var buf bytes.Buffer
value := cell.Value

knownName, nameOk := cell.Metadata["name"]
labelCommentForCell := labelCommentPreamble + knownName + "\n"

isFencedCodeBlock, err := strconv.ParseBool(cell.Metadata[PrefixAttributeName(InternalAttributePrefix, "fenced")])
if err == nil && !isFencedCodeBlock {
for _, v := range strings.Split(value, "\n") {
lines := strings.Split(value, "\n")
if labelComment && nameOk && len(lines) > 0 {
_, _ = buf.Write(bytes.Repeat([]byte{' '}, 4))
_, _ = buf.WriteString(labelCommentForCell)
}

for _, v := range lines {
_, _ = buf.Write(bytes.Repeat([]byte{' '}, 4))
_, _ = buf.WriteString(v)
_ = buf.WriteByte('\n')
Expand All @@ -391,6 +401,9 @@ func serializeCellCodeBlock(w io.Writer, cell *Cell) error {
}

_ = buf.WriteByte('\n')
if labelComment && nameOk {
_, _ = buf.WriteString(labelCommentForCell)
}
_, _ = buf.WriteString(cell.Value)
_ = buf.WriteByte('\n')

Expand Down
35 changes: 23 additions & 12 deletions pkg/document/editor/cell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ def hello():
assert.Equal(t, "def hello():\n print(\"Hello World\")", cell.Value)
}

func mustReturnSerializedCells(t *testing.T, cells []*Cell) []byte {
func mustReturnSerializedCells(t *testing.T, cells []*Cell, labelComment bool) []byte {
t.Helper()

data, err := serializeCells(cells)
data, err := serializeCells(cells, labelComment)
require.NoError(t, err)

return data
Expand Down Expand Up @@ -193,7 +193,7 @@ Last paragraph.
assert.Equal(
t,
"# New header\n\n1. Item 1\n2. Item 2\n3. Item 3\n\nLast paragraph.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})

Expand All @@ -203,7 +203,7 @@ Last paragraph.
assert.Equal(
t,
"# Examples\n\n1. Item 1\n2. Item 2\n3. Item 3\n4. Item 4\n\nLast paragraph.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})

Expand All @@ -220,7 +220,7 @@ Last paragraph.
assert.Equal(
t,
"# Title\n\n# Examples\n\n1. Item 1\n2. Item 2\n3. Item 3\n\nLast paragraph.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})

Expand All @@ -235,7 +235,7 @@ Last paragraph.
assert.Equal(
t,
"# Examples\n\nA new paragraph.\n\n1. Item 1\n2. Item 2\n3. Item 3\n\nLast paragraph.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})

Expand All @@ -249,7 +249,7 @@ Last paragraph.
assert.Equal(
t,
"# Examples\n\n1. Item 1\n2. Item 2\n3. Item 3\n\nLast paragraph.\n\nParagraph after the last one.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})
})
Expand All @@ -260,7 +260,7 @@ Last paragraph.
assert.Equal(
t,
"# Examples\n\nLast paragraph.\n",
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
})
}
Expand Down Expand Up @@ -304,7 +304,7 @@ brew bundle --no-lock
pre-commit install
`+"```"+`
`,
string(mustReturnSerializedCells(t, cells)),
string(mustReturnSerializedCells(t, cells, false)),
)
}

Expand All @@ -315,7 +315,7 @@ func Test_serializeCells(t *testing.T) {
node, err := doc.Root()
require.NoError(t, err)
cells := toCells(doc, node, data)
assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells)))
assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells, false)))
})

t.Run("privateFields", func(t *testing.T) {
Expand All @@ -329,7 +329,7 @@ func Test_serializeCells(t *testing.T) {
cells[0].Metadata["_private"] = "private"
cells[0].Metadata["runme.dev/internal"] = "internal"

assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells)))
assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells, false)))
})

t.Run("UnsupportedLang", func(t *testing.T) {
Expand All @@ -344,7 +344,7 @@ def hello():
node, err := doc.Root()
require.NoError(t, err)
cells := toCells(doc, node, data)
assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells)))
assert.Equal(t, string(data), string(mustReturnSerializedCells(t, cells, false)))
})
}

Expand Down Expand Up @@ -418,3 +418,14 @@ func Test_serializeOutputs(t *testing.T) {
assert.Equal(t, "\n\n![$ curl -s \"https://runme.dev/runme_cube.svg\"](data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTUzNSIgaGVpZ2h0PSI4MDA0IiB2aWV3Qm94PSIwIDAgOTUzNSA4MDA0IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNNTA0Ni45NCAzMy43Mzk1QzQ4MzIuNDYgLTE2LjQwNjEgNDQ5MS42OSAtOS43ODk5IDQyODYuNTkgNDcuODI2NkwzNTA0IDI2OC42MUwyNzIxLjQyIDQ4OS4zOTJMMTE1Ni4yNSA5MzAuOTU4Qzk1MS4zMSA5ODguNTc1IDk1OC4wOTIgMTA3Ni40OSAxMTcyLjQ2IDExMjYuNDdMNDQzMS44NCAxODg3Ljk0QzQ2NDUuNDcgMTkzNy43OSA0OTg2LjE1IDE5MzEuMzQgNTE5MS4wOSAxODczLjU1TDU5NzMuNzUgMTY1Mi43Nkw2NzU2LjQyIDE0MzEuOTdMNzUzOS4wOSAxMjExLjE4TDgzMjEuNzYgOTkwLjM5NEM4NTI2LjcgOTMyLjc3OCA4NTE5LjkyIDg0NS4wNTcgODMwNi4zOCA3OTUuMjE1TDUwNDYuOTQgMzMuNzM5NVoiIGZpbGw9IiM1QjNBREYiIGZpbGwtb3BhY2l0eT0iMC43Ii8)\n", buf.String())
})
}

func Test_removeLabelCommentOnCells(t *testing.T) {
data := []byte("```sh {\"first\":\"\",\"name\":\"label-in-comments\",\"second\":\"2\"}\n### Exported in runme.dev as label-in-comments\necho 1\n```\n")
doc := document.New(data, identityResolverNone)
node, err := doc.Root()
require.NoError(t, err)

cells := toCells(doc, node, data)

require.NotContains(t, cells[0].Value, "### Exported in runme.dev as label-in-comments")
}
7 changes: 6 additions & 1 deletion pkg/document/editor/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,13 @@ func Serialize(notebook *Notebook, outputMetadata *document.RunmeMetadata, opts
)
}

labelComment := false
if frontmatter != nil && frontmatter.Shell == "dagger shell" {
labelComment = true
}

// Serialize cells.
serializedCells, err := serializeCells(notebook.Cells)
serializedCells, err := serializeCells(notebook.Cells, labelComment)
if err != nil {
return nil, err
}
Expand Down
44 changes: 44 additions & 0 deletions pkg/document/editor/editor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,3 +752,47 @@ func TestEditor_AttributeFormat(t *testing.T) {
)
})
}

func TestEditor_LabelComments(t *testing.T) {
labelComments := []byte("## Retain attribute format\n\nFirst block uses HTML.\n\n```sh { name=date interactive=false }\n### Exported in runme.dev as date\ndate\n```\n\nThe second JSON.\n\n```javascript {\"interactive\":\"false\",\"name\":\"iso\"}\n### Exported in runme.dev as iso\nconsole.log(new Date().toISOString())\n```\n")
t.Run("StrippedByDefault", func(t *testing.T) {

notebook, err := Deserialize(labelComments, Options{IdentityResolver: identityResolverNone})
require.NoError(t, err)

assert.Nil(t, notebook.Frontmatter)

assert.Equal(t, "date", notebook.Cells[2].Metadata["name"])
require.NotContains(t, notebook.Cells[2].Value, labelCommentPreamble)

assert.Equal(t, "iso", notebook.Cells[4].Metadata["name"])
require.NotContains(t, notebook.Cells[4].Value, labelCommentPreamble)

actual, err := Serialize(notebook, nil, Options{})
require.NoError(t, err)

require.NotContains(t, string(actual), labelCommentPreamble+"date")
require.NotContains(t, string(actual), labelCommentPreamble+"iso")
})

t.Run("SerializeForDaggerShell", func(t *testing.T) {
withFrontmatter := bytes.Join([][]byte{[]byte("---\nshell: dagger shell\n---\n\n"), labelComments}, nil)

notebook, err := Deserialize(withFrontmatter, Options{IdentityResolver: identityResolverNone})
require.NoError(t, err)

assert.Equal(t, "dagger shell", notebook.Frontmatter.Shell)

assert.Equal(t, "date", notebook.Cells[2].Metadata["name"])
require.NotContains(t, notebook.Cells[2].Value, labelCommentPreamble)

assert.Equal(t, "iso", notebook.Cells[4].Metadata["name"])
require.NotContains(t, notebook.Cells[4].Value, labelCommentPreamble)

actual, err := Serialize(notebook, nil, Options{})
require.NoError(t, err)

require.Contains(t, string(actual), labelCommentPreamble+"date")
require.Contains(t, string(actual), labelCommentPreamble+"iso")
})
}

0 comments on commit 828abc8

Please sign in to comment.