Skip to content

Commit

Permalink
fix: Better rendering of flexible spaces in docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
jwalton committed Sep 21, 2022
1 parent 1c7988c commit 37cd245
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 42 deletions.
7 changes: 7 additions & 0 deletions docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
77 changes: 50 additions & 27 deletions docs/src/remark/kitschPromptPreview.ts
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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}"`;
}

Expand All @@ -73,30 +80,46 @@ 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 `<div class="kitschPromptLine"><span class="kitchPromptLinePart">${parts
.map(convertToHtml)
.join('</span><span class="kitchPromptLinePart">')}</span></div>`;
} else {
return convertToHtml(line);
}
});

html = html.replace(/\n/g, "<br/>");
html = splitLines.join("");

return html;
} catch (err) {
return escapeMdx("Error running example: " + err.stack);
}
}

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) => {
Expand Down
28 changes: 19 additions & 9 deletions internal/kitsch/modules/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
}
}

Expand Down
7 changes: 6 additions & 1 deletion internal/kitsch/modules/flexible_space.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
11 changes: 7 additions & 4 deletions internal/kitsch/modules/flexible_space_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
2 changes: 1 addition & 1 deletion internal/kitsch/modules/moduleWrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}) {
Expand Down

0 comments on commit 37cd245

Please sign in to comment.