diff --git a/internal/cmd/preprocessor/cmd/code_node.go b/internal/cmd/preprocessor/cmd/code_node.go new file mode 100644 index 000000000..c66845b1f --- /dev/null +++ b/internal/cmd/preprocessor/cmd/code_node.go @@ -0,0 +1,84 @@ +// Copyright 2023 The CUE Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "bytes" + "fmt" +) + +const ( + fnCode = "code" +) + +// A codeNode is used to create a simple ```-based code block for a single file +// whose contents are formatted. This ensures good formatting but also valid +// code. +type codeNode struct { + txtarNode +} + +func (c *codeNode) nodeType() string { + return fnCode +} + +var _ runnableNode = (*codeNode)(nil) + +type codeNodeRunContext struct { + *txtarRunContext +} + +func (s *codeNode) validate() error { + if l := len(s.analysis.fileNames); l != 1 { + return fmt.Errorf("code nodes can only contain one file in the txtar archive") + } + return nil +} + +func (s *codeNode) run() runnable { + return &codeNodeRunContext{ + txtarRunContext: &txtarRunContext{ + txtarNode: s.txtarNode, + executionContext: s.executionContext, + bufferedErrorContext: &errorContextBuffer{ + executionContext: s.executionContext, + }, + }, + } +} + +func (s *codeNodeRunContext) run() (err error) { + defer recoverFatalError(&err) + + if err := s.formatFiles(); err != nil { + return errorIfInError(s) + } + + return nil +} + +func (s *codeNode) writeTransformTo(b *bytes.Buffer) error { + p := bufPrintf(b) + + // There will only be one file + a := s.analysis.fileNames[0] + f := s.effectiveArchive.Files[0] + + // TODO tidy up templating etc + p("```%s\n", a.Language) + p("%s", f.Data) + p("```") + return nil +} diff --git a/internal/cmd/preprocessor/cmd/parse.go b/internal/cmd/preprocessor/cmd/parse.go index 3ce4d60a4..6c092a636 100644 --- a/internal/cmd/preprocessor/cmd/parse.go +++ b/internal/cmd/preprocessor/cmd/parse.go @@ -192,6 +192,12 @@ func (rf *rootFile) parse_WithNode(n *parse.WithNode) (node, error) { return nil, err } return &sidebysideNode{txtarNode: t}, nil + case fnCode: + t, err := rf.parse_txtarNode(n, fn.Ident, c.Args[1:]) + if err != nil { + return nil, err + } + return &codeNode{txtarNode: t}, nil case fnStep: // Increment first because we are numbering from 1 rf.stepNumber++ diff --git a/internal/cmd/preprocessor/cmd/rootfile.go b/internal/cmd/preprocessor/cmd/rootfile.go index 8968ab661..186f1f52a 100644 --- a/internal/cmd/preprocessor/cmd/rootfile.go +++ b/internal/cmd/preprocessor/cmd/rootfile.go @@ -43,6 +43,7 @@ var ( // were function calls. templateFunctions = map[string]any{ fnSidebyside: true, + fnCode: true, fnStep: true, fnUpload: true, fnScript: true, diff --git a/internal/cmd/preprocessor/cmd/testdata/execute_transform.txtar b/internal/cmd/preprocessor/cmd/testdata/execute_transform.txtar index 9dadd9dfd..d73c003b2 100644 --- a/internal/cmd/preprocessor/cmd/testdata/execute_transform.txtar +++ b/internal/cmd/preprocessor/cmd/testdata/execute_transform.txtar @@ -65,6 +65,10 @@ package site > >{{{with step}}} >some text +>{{{with code "en" "x.cue example"}}} +>-- x.cue -- +>x: 5 +>{{{end}}} >{{{end}}} > >Some text after @@ -98,6 +102,9 @@ map: { {{< step stepNumber="2" >}} some text +```text +x: 5 +``` {{< /step >}} Some text after