diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css
index ad85f32..c8770e0 100644
--- a/docs/src/css/custom.css
+++ b/docs/src/css/custom.css
@@ -31,3 +31,10 @@
html[data-theme='dark'] .docusaurus-highlight-code-line {
background-color: rgba(0, 0, 0, 0.3);
}
+
+.kitschPromptLine {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+}
\ No newline at end of file
diff --git a/docs/src/remark/kitschPromptPreview.ts b/docs/src/remark/kitschPromptPreview.ts
index 9547fa4..bc19fc6 100644
--- a/docs/src/remark/kitschPromptPreview.ts
+++ b/docs/src/remark/kitschPromptPreview.ts
@@ -1,14 +1,15 @@
import Convert from "ansi-to-html";
import { execSync } from "child_process";
+import escapeHtml from "escape-html";
import * as fs from "fs";
import { Code, Parent } from "mdast";
+import path from "path";
import tmp from "tmp";
import { Transformer } from "unified";
import visit from "unist-util-visit";
-import escapeHtml from "escape-html";
-import path from "path";
const KITSCH = process.env.KITSCH || "kitsch";
+const FLEX_SPACE = "--space--";
const convert = new Convert({
fg: "#cccccc",
@@ -40,27 +41,33 @@ function execCombined(
function runKitschPrompt(exmaple: string): string {
const configParts = exmaple.split("---");
- let demo: string;
- let config: string;
+ let demoContext: string;
+ let kitschConfig: string;
+
if (configParts.length === 2) {
- demo = configParts[0];
- config = configParts[1];
+ demoContext = configParts[0];
+ kitschConfig = configParts[1];
} else {
- demo = "";
- config = configParts[0];
+ demoContext = "";
+ kitschConfig = configParts[0];
}
+ demoContext += `\nflexibleSpaceReplacement: '${FLEX_SPACE}'`;
+
// Fix the CWD to be the root of the docs folder.
- config = config.replace(/\${CWD}/g, path.join(__dirname, "..", ".."));
+ kitschConfig = kitschConfig.replace(
+ /\${CWD}/g,
+ path.join(__dirname, "..", "..")
+ );
// Copy the example to a temporary file
const demoFile = tmp.fileSync({ postfix: ".yaml" });
- fs.writeFileSync(demoFile.name, demo);
+ fs.writeFileSync(demoFile.name, demoContext);
let options = "";
- if (config.trim()) {
+ if (kitschConfig.trim()) {
const configFile = tmp.fileSync({ postfix: ".yaml" });
- fs.writeFileSync(configFile.name, config);
+ fs.writeFileSync(configFile.name, kitschConfig);
options += ` --config "${configFile.name}"`;
}
@@ -73,23 +80,20 @@ function runKitschPrompt(exmaple: string): string {
let html = escapeMdx(output);
- // Convert ANSI to HTML.
- html = convert.toHtml(html);
-
- // Fix each style tag to be a JSX style tag.
- html = html.replace(/style="([^"]*)"/g, (match, style) => {
- const reactStyle = style
- .split(";")
- .map((s) => {
- const [key, value] = s.split(":");
- return `"${key}": "${value}"`;
- })
- .join(",");
-
- return `style={{${reactStyle}}}`;
+ // Split up lines at flexible spaces.
+ const lines = html.split("\n");
+ const splitLines = lines.map((line) => {
+ const parts = line.split(FLEX_SPACE);
+ if (parts.length > 1) {
+ return `
${parts
+ .map(convertToHtml)
+ .join('')}
`;
+ } else {
+ return convertToHtml(line);
+ }
});
- html = html.replace(/\n/g, "
");
+ html = splitLines.join("");
return html;
} catch (err) {
@@ -97,6 +101,25 @@ function runKitschPrompt(exmaple: string): string {
}
}
+export function convertToHtml(ansi: string) {
+ // Convert ANSI to HTML.
+ let html = convert.toHtml(ansi);
+
+ // Fix each style tag to be a JSX style tag.
+ html = html.replace(/style="([^"]*)"/g, (match, style) => {
+ const reactStyle = style
+ .split(";")
+ .map((s) => {
+ const [key, value] = s.split(":");
+ return `"${key}": "${value}"`;
+ })
+ .join(",");
+
+ return `style={{${reactStyle}}}`;
+ });
+ return html;
+}
+
export default function kitschPromptPreview(): Transformer {
const transformer: Transformer = async (ast) => {
// visit(ast, "jsx", (node: Literal, index: number, parent: Parent) => {
diff --git a/internal/kitsch/modules/context.go b/internal/kitsch/modules/context.go
index af004e1..37e37ab 100644
--- a/internal/kitsch/modules/context.go
+++ b/internal/kitsch/modules/context.go
@@ -128,6 +128,10 @@ type Context struct {
Styles *styling.Registry
// DefaultTimeout is the default module timeout.
DefaultTimeout time.Duration
+ // FlexibleSpaceReplacement is a string to use to replace flexible spaces.
+ // If set, flexible spaces will be replaced with this sentinel value.
+ // See DemoConfig.FlexibleSpaceReplacement for details.
+ FlexibleSpaceReplacement string
mutex sync.Mutex
gitInitialized bool
@@ -214,6 +218,11 @@ type DemoConfig struct {
Git gitutils.DemoGit `yaml:"git"`
// CWDIsReadOnly is true if the current working directory is read-only.
CWDIsReadOnly bool `yaml:"cwdIsReadOnly"`
+ // FlexibleSpaceReplacement is a string to use to replace flexible spaces.
+ // This is only used when generating documentation - we replace flexible spaces
+ // with a sentinel value, and then in documentation generation we can use
+ // flexbox to make flexible spaces look good in the docs.
+ FlexibleSpaceReplacement string `yaml:"flexibleSpaceReplacement"`
}
// Load will load the demo configuration from the specified file.
@@ -259,15 +268,16 @@ func NewDemoContext(
}
return Context{
- Globals: config.Globals,
- Directory: fileutils.NewDirectoryTestFS(config.Globals.CWD, demoFsys),
- Environment: env.DummyEnv{Env: config.Env},
- ProjectTypes: []projects.ProjectType{},
- ValueCache: cache.NewMemoryCache(),
- Styles: styles,
- gitInitialized: true,
- git: config.Git,
- DefaultTimeout: 1000 * time.Millisecond,
+ Globals: config.Globals,
+ Directory: fileutils.NewDirectoryTestFS(config.Globals.CWD, demoFsys),
+ Environment: env.DummyEnv{Env: config.Env},
+ ProjectTypes: []projects.ProjectType{},
+ ValueCache: cache.NewMemoryCache(),
+ Styles: styles,
+ gitInitialized: true,
+ git: config.Git,
+ DefaultTimeout: 1000 * time.Millisecond,
+ FlexibleSpaceReplacement: config.FlexibleSpaceReplacement,
}
}
diff --git a/internal/kitsch/modules/flexible_space.go b/internal/kitsch/modules/flexible_space.go
index 4380788..bd04230 100644
--- a/internal/kitsch/modules/flexible_space.go
+++ b/internal/kitsch/modules/flexible_space.go
@@ -59,9 +59,14 @@ func init() {
}
// processFlexibleSpaces replaces flexible space markers with spaces.
-func processFlexibleSpaces(terminalWidth int, renderedPrompt string) string {
+func processFlexibleSpaces(terminalWidth int, renderedPrompt string, replacement string) string {
result := ""
+ if replacement != "" {
+ // Just replace all the flexible space markers with the provided sentinel value.
+ return strings.ReplaceAll(renderedPrompt, flexibleSpaceMarker, replacement)
+ }
+
// Split into lines.
lines := strings.Split(renderedPrompt, "\n")
for lineIndex, line := range lines {
diff --git a/internal/kitsch/modules/flexible_space_test.go b/internal/kitsch/modules/flexible_space_test.go
index d293895..b60b23e 100644
--- a/internal/kitsch/modules/flexible_space_test.go
+++ b/internal/kitsch/modules/flexible_space_test.go
@@ -7,15 +7,18 @@ import (
)
func TestProcessFlexibleSpaces(t *testing.T) {
- result := processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b")
+ result := processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b", "")
assert.Equal(t, "a b", result)
- result = processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b\n$ ")
+ result = processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b\n$ ", "")
assert.Equal(t, "a b\n$ ", result)
- result = processFlexibleSpaces(10, "ab")
+ result = processFlexibleSpaces(10, "ab", "")
assert.Equal(t, "ab", result)
- result = processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b"+flexibleSpaceMarker+"c")
+ result = processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b"+flexibleSpaceMarker+"c", "")
assert.Equal(t, "a b c", result)
+
+ result = processFlexibleSpaces(10, "a"+flexibleSpaceMarker+"b"+flexibleSpaceMarker+"c", "foo")
+ assert.Equal(t, "afoobfooc", result)
}
diff --git a/internal/kitsch/modules/moduleWrapper.go b/internal/kitsch/modules/moduleWrapper.go
index b9cb7a3..12ccf54 100644
--- a/internal/kitsch/modules/moduleWrapper.go
+++ b/internal/kitsch/modules/moduleWrapper.go
@@ -214,7 +214,7 @@ func processModuleResult(
// RenderPrompt renders the top-level module in a prompt.
func RenderPrompt(context *Context, root ModuleWrapper) (ModuleWrapperResult, string) {
result := root.Execute(context)
- return result, processFlexibleSpaces(context.Globals.TerminalWidth, result.Text)
+ return result, processFlexibleSpaces(context.Globals.TerminalWidth, result.Text, context.FlexibleSpaceReplacement)
}
// func testTemplate(context *Context, prefix string, template string, dataMap map[string]interface{}) {