Skip to content

Commit

Permalink
introduce @Class close #64
Browse files Browse the repository at this point in the history
  • Loading branch information
JSer committed Apr 11, 2024
1 parent cce9c4f commit bdb29c7
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 3 deletions.
16 changes: 16 additions & 0 deletions examples/web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,22 @@ pre.shaku .line.diff-delete::before {
lang="js"
shakuEnabled
/>
<h3>Custom class names for lines</h3>
<p>
Sometimes you might want to add custom class names for a line, this
could be easily done by <code>@class</code> directive.
</p>
<CodeBlock
code={`// @class custom-class1 custom-class2 !
// @class custom-class1 custom-class2
// @highlight
const Hello = "World!"
// ^
// [Open the dev console and inspect this line,]
// [you'll see this line is rendered with the custom class names!]`}
lang="js"
shakuEnabled
/>
<$.h2 $textAlign="center">Dev Tools</$.h2>
<p>
We got some tools to understand how Shaku works, such as{" "}
Expand Down
16 changes: 16 additions & 0 deletions examples/web/components/Playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ const Hello = "World!"
// [and \`!\` is removed when rendered.]
\`\`\`
## Custom class names
Sometimes you might want to add custom class names for a line, this
could be easily done by \`@class\` directive.
\`\`\`tsx annotate
// @class custom-class1 custom-class2 !
// @class custom-class1 custom-class2
// @highlight
const Hello = "World!"
// ^
// [Open the dev console and inspect this line,]
// [you'll see this line is rendered with the custom class names!]
\`\`\`
## How to Use
Visit [shaku on github](https://github.com/JSerZANP/shaku/tree/main) to find the right plugin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,56 @@ exports[`parseLine() can parse comment lines > (1)(1)(10) 1`] = `
}
`;

exports[`parseLine() can parse comment lines > @class a 1`] = `
{
"config": {
"classNames": "a",
"isEscaped": false,
},
"type": "DirectiveClass",
}
`;

exports[`parseLine() can parse comment lines > @class a! 1`] = `
{
"config": {
"classNames": "a",
"isEscaped": true,
},
"type": "DirectiveClass",
}
`;

exports[`parseLine() can parse comment lines > @class abc efg h123 1`] = `
{
"config": {
"classNames": "abc efg h123",
"isEscaped": false,
},
"type": "DirectiveClass",
}
`;

exports[`parseLine() can parse comment lines > @class abc efg h123! 1`] = `
{
"config": {
"classNames": "abc efg h123",
"isEscaped": true,
},
"type": "DirectiveClass",
}
`;

exports[`parseLine() can parse comment lines > @class abc-1 efg-2 h123! 1`] = `
{
"config": {
"classNames": "abc-1 efg-2 h123",
"isEscaped": true,
},
"type": "DirectiveClass",
}
`;

exports[`parseLine() can parse comment lines > @diff 1`] = `null`;

exports[`parseLine() can parse comment lines > @diff - ^ 1`] = `
Expand Down
5 changes: 5 additions & 0 deletions packages/shaku-code-annotate-core/src/__tests__/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ describe("parseLine() can parse comment lines", () => {
"@diff - ^ ",
" (r)(g)(b) ",
" (red) (green) (blue) ",
"@class a",
"@class a! ",
"@class abc efg h123 ",
"@class abc efg h123!",
"@class abc-1 efg-2 h123!",
];
for (const input of inputs) {
test(input, () => {
Expand Down
27 changes: 26 additions & 1 deletion packages/shaku-code-annotate-core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ export type ShakuDirectiveDiff = {
const RegShakuDirectiveDiff =
/^(?<leadingSpaces>\s*)@diff\s+(?<type>(\+|\-))\s*((?<mark>([a-z\^]+)?)\s*)?(?<escape>!?)\s*$/;

export type ShakuDirectiveClass = {
type: "DirectiveClass";
config: {
isEscaped: boolean;
classNames: string;
};
};

const RegShakuDirectiveClass =
/^(?<leadingSpaces>\s*)@class\s+(?<classNames>([a-zA-Z0-9 \-_]+))\s*(?<escape>!?)\s*$/;

export type ShakuLine =
| ShakuDirectiveUnderline
| ShakuAnnotationLine
Expand All @@ -139,7 +150,8 @@ export type ShakuLine =
| ShakuDirectiveDim
| ShakuDirectiveFocus
| ShakuDirectiveHighlightInline
| ShakuDirectiveDiff;
| ShakuDirectiveDiff
| ShakuDirectiveClass;

export const parseLine = (line: string): ShakuLine | null => {
const matchShakuDirectiveUnderlineSolid = line.match(
Expand Down Expand Up @@ -322,6 +334,19 @@ export const parseLine = (line: string): ShakuLine | null => {
};
}

const matchShakuDirectiveClass = line.match(RegShakuDirectiveClass);
if (matchShakuDirectiveClass) {
const classNames = matchShakuDirectiveClass.groups?.classNames ?? "";

return {
type: "DirectiveClass",
config: {
isEscaped: !!matchShakuDirectiveClass.groups?.escape,
classNames: classNames.trim(),
},
};
}

return null;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ exports[`codeToHtml() + raw HTML 3`] = `
}
`;

exports[`codeToHtml() + raw HTML 4`] = `
{
"html": "<pre class=\\"shiki shaku github-light\\" style=\\"color:#24292e;background-color:#fff\\"><div class=\\"code-container\\"><code><div class=\\"line\\"></div><div class=\\"line highlight abc h123\\"><span style=\\"color: #D73A49\\">function</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useSomeEffect</span><span style=\\"color: #24292E\\">({</span><span style=\\"color: #E36209\\">blog</span><span style=\\"color: #24292E\\">}) {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useEffect</span><span style=\\"color: #24292E\\">(() </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #D73A49\\">return</span><span style=\\"color: #24292E\\"> () </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> location.href </span><span style=\\"color: #D73A49\\">=</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #032F62\\">&#039;https://jser.dev&#039;</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> }</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> }, [blog])</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\">}</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span></div></code></div></pre>",
"skipped": false,
}
`;

exports[`codeToHtml() 1`] = `
{
"html": "<pre class=\\"shiki shaku github-light\\" style=\\"color:#24292e;background-color:#fff\\"><div class=\\"code-container\\"><code><div class=\\"line\\"></div><div class=\\"line\\"><span style=\\"color: #D73A49\\">function</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">ChatRoom</span><span style=\\"color: #24292E\\">({ </span><span style=\\"color: #E36209\\">roomId</span><span style=\\"color: #24292E\\"> }) {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #D73A49\\">const</span><span style=\\"color: #24292E\\"> [</span><span style=\\"color: #005CC5\\">serverUrl</span><span style=\\"color: #24292E\\">, </span><span style=\\"color: #005CC5\\">setServerUrl</span><span style=\\"color: #24292E\\">] </span><span style=\\"color: #D73A49\\">=</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useState</span><span style=\\"color: #24292E\\">(</span><span style=\\"color: #032F62\\">&#039;https://localhost:1234&#039;</span><span style=\\"color: #24292E\\">);</span></div><div class=\\"shaku-callout\\" style=\\"left:5ch\\"><span class=\\"shaku-callout-arrow\\" style=\\"left:6ch\\"></span>&lt;a href=&quot;https:jser.dev&quot;&gt;jser.dev&lt;/a&gt;</div><div class=\\"line\\"></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useEffect</span><span style=\\"color: #24292E\\">(() </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><mark class=\\"shaku-inline-highlight\\" ><span style=\\"color: #D73A49\\">const</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #005CC5\\">connection</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #D73A49\\">=</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">createConnection</span><span style=\\"color: #24292E\\">(serverUrl, roomId);</span></mark></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><mark class=\\"shaku-inline-highlight\\" data-id=\\"1\\"><span style=\\"color: #24292E\\">connection.</span><span style=\\"color: #6F42C1\\">connect</span><span style=\\"color: #24292E\\">(</span></mark><span style=\\"color: #24292E\\">);</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #D73A49\\">return</span><span style=\\"color: #24292E\\"> () </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><mark class=\\"shaku-inline-highlight\\" data-id=\\"2\\"><span style=\\"color: #24292E\\">connection.</span><span style=\\"color: #6F42C1\\">disconnect</span><span style=\\"color: #24292E\\">()</span></mark><span style=\\"color: #24292E\\">;</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> };</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> }, </span><mark class=\\"shaku-inline-highlight\\" data-id=\\"3\\"><span style=\\"color: #24292E\\">[serverUrl, roomId])</span></mark><span style=\\"color: #24292E\\">;</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\">}</span></div><div class=\\"line\\"></div></code></div></pre>",
Expand All @@ -41,3 +48,10 @@ exports[`codeToHtml() 3`] = `
"skipped": false,
}
`;

exports[`codeToHtml() 4`] = `
{
"html": "<pre class=\\"shiki shaku github-light\\" style=\\"color:#24292e;background-color:#fff\\"><div class=\\"code-container\\"><code><div class=\\"line\\"></div><div class=\\"line highlight abc h123\\"><span style=\\"color: #D73A49\\">function</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useSomeEffect</span><span style=\\"color: #24292E\\">({</span><span style=\\"color: #E36209\\">blog</span><span style=\\"color: #24292E\\">}) {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #6F42C1\\">useEffect</span><span style=\\"color: #24292E\\">(() </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span><span style=\\"color: #D73A49\\">return</span><span style=\\"color: #24292E\\"> () </span><span style=\\"color: #D73A49\\">=&gt;</span><span style=\\"color: #24292E\\"> {</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> location.href </span><span style=\\"color: #D73A49\\">=</span><span style=\\"color: #24292E\\"> </span><span style=\\"color: #032F62\\">&#039;https://jser.dev&#039;</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> }</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> }, [blog])</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\">}</span></div><div class=\\"line\\"><span style=\\"color: #24292E\\"> </span></div></code></div></pre>",
"skipped": false,
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ function useSomeEffect({blog}) {
}
// @fold ^
}, [blog])
}
`,

`
// @class abc h123
// @highlight
function useSomeEffect({blog}) {
useEffect(() => {
return () => {
location.href = 'https://jser.dev'
}
}, [blog])
}
`,
];
Expand Down
11 changes: 10 additions & 1 deletion packages/shaku-code-annotate-shiki/src/codeToShakuHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export let codeToShakuHtml = function (
let diffNextSourceLine: false | "+" | "-" = false;
let diffBlock: false | "+" | "-" = false;
let isFoldBlock = false;
let classNamesForNextSourceLine = "";

for (let i = 0; i < parsedLines.length; i++) {
const line = parsedLines[i];
Expand Down Expand Up @@ -305,6 +306,10 @@ export let codeToShakuHtml = function (
}
break;
}
case "DirectiveClass": {
classNamesForNextSourceLine = shakuLine.config.classNames;
break;
}
default:
assertsNever(shakuLine);
}
Expand All @@ -315,11 +320,15 @@ export let codeToShakuHtml = function (
const shouldDim =
isDimBlock || shouldDimNextSourceLine || (hasFocus && !shouldFocus);
const diff = diffBlock || diffNextSourceLine;
const classNames = classNamesForNextSourceLine
? " " + classNamesForNextSourceLine
: "";

shouldHighlighNextSourceLine = false;
shouldFocusNextSourceLine = false;
shouldDimNextSourceLine = false;
diffNextSourceLine = false;
classNamesForNextSourceLine = "";

const sourceLine = line.type === "default" ? line.line : line.sourceLine;

Expand All @@ -332,7 +341,7 @@ export let codeToShakuHtml = function (
? " diff diff-delete"
: "";

const prefix = `<div class="line${highlightClass}${dimClass}${diffClass}">`;
const prefix = `<div class="line${highlightClass}${dimClass}${diffClass}${classNames}">`;
html += prefix;

if (shakuDirectiveHighlightInline) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ exports[`highlight() 3`] = `
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">}</span><span class=\\"sh__token--break\\" style=\\"color: var(--sh-break)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span></div></code></pre>"
`;
exports[`highlight() 4`] = `
"<pre class=\\"shaku\\"><code><div class=\\"sh__line\\"><span class=\\"sh__token--break\\" style=\\"color: var(--sh-break)\\">
</span></div><div class=\\"sh__line highlight abc e123\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--keyword\\" style=\\"color: var(--sh-keyword)\\">function</span><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--identifier\\" style=\\"color: var(--sh-identifier)\\">hello</span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">(</span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">)</span><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">{</span><span class=\\"sh__token--break\\" style=\\"color: var(--sh-break)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--keyword\\" style=\\"color: var(--sh-keyword)\\">return</span><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">&lt;</span><span class=\\"sh__token--identifier\\" style=\\"color: var(--sh-identifier)\\">div</span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">&gt;</span><span class=\\"sh__token--jsxliterals\\" style=\\"color: var(--sh-jsxliterals)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--jsxliterals\\" style=\\"color: var(--sh-jsxliterals)\\"> Hello world!</span><span class=\\"sh__token--jsxliterals\\" style=\\"color: var(--sh-jsxliterals)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--jsxliterals\\" style=\\"color: var(--sh-jsxliterals)\\"> </span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">&lt;/</span><span class=\\"sh__token--identifier\\" style=\\"color: var(--sh-identifier)\\">div</span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">&gt;</span><span class=\\"sh__token--break\\" style=\\"color: var(--sh-break)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span><span class=\\"sh__token--sign\\" style=\\"color: var(--sh-sign)\\">}</span><span class=\\"sh__token--break\\" style=\\"color: var(--sh-break)\\">
</span></div><div class=\\"sh__line\\"><span class=\\"sh__token--space\\" style=\\"color: var(--sh-space)\\"> </span></div></code></pre>"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ function hello() {
</div>
}
`,
`
// @highlight
// @class abc e123
function hello() {
return <div>
Hello world!
</div>
}
`,
];

test("highlight()", async () => {
Expand Down
11 changes: 10 additions & 1 deletion packages/shaku-code-annotate-sugar-high/src/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function highlight(code: string) {
} = null;
let diffNextSourceLine: false | "+" | "-" = false;
let diffBlock: false | "+" | "-" = false;
let classNamesForNextSourceLine = "";

for (let i = 0; i < parsedLines.length; i++) {
const line = parsedLines[i];
Expand Down Expand Up @@ -204,6 +205,10 @@ export function highlight(code: string) {
}
break;
}
case "DirectiveClass": {
classNamesForNextSourceLine = shakuLine.config.classNames;
break;
}
default:
assertsNever(shakuLine);
}
Expand All @@ -214,11 +219,15 @@ export function highlight(code: string) {
const shouldDim =
isDimBlock || shouldDimNextSourceLine || (hasFocus && !shouldFocus);
const diff = diffBlock || diffNextSourceLine;
const classNames = classNamesForNextSourceLine
? " " + classNamesForNextSourceLine
: "";

shouldHighlighNextSourceLine = false;
shouldFocusNextSourceLine = false;
shouldDimNextSourceLine = false;
diffNextSourceLine = false;
classNamesForNextSourceLine = "";

const sourceLine = line.type === "default" ? line.line : line.sourceLine;

Expand All @@ -230,7 +239,7 @@ export function highlight(code: string) {
: diff === "-"
? " diff diff-delete"
: "";
const prefix = `<div class="sh__line${highlightClass}${dimClass}${diffClass}">`;
const prefix = `<div class="sh__line${highlightClass}${dimClass}${diffClass}${classNames}">`;
html += prefix;

if (shakuDirectiveHighlightInline) {
Expand Down

0 comments on commit bdb29c7

Please sign in to comment.