Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions api/build/BuildRunner.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,19 @@ component accessors=true {

arguments.builder.injectMethod = this.injectMethod;

arguments.builder.injectMethod( "renderLinks", function( required string text ){
return new api.rendering.WikiLinksRenderer( docTree=variables.docTree ).renderLinks( text=arguments.text, builder=variables._builder );
arguments.builder.injectMethod( "renderLinks", function( required string text, required struct args, boolean markdown=false ){
return new api.rendering.WikiLinksRenderer( docTree=variables.docTree ).renderLinks(
text = arguments.text,
builder = variables._builder,
args = arguments.args,
markdown = arguments.markdown
);
} );
arguments.builder.injectMethod( "renderTemplate", function( required string template, struct args={} ){
arguments.builder.injectMethod( "renderTemplate", function( required string template, struct args={}, boolean markdown=false ){
var renderer = new api.rendering.TemplateRenderer();
var rendered = renderer.render( argumentCollection=arguments, template=_rootPathForRenderer & arguments.template );
var rendered = renderer.render( argumentCollection=arguments, template=_rootPathForRenderer & arguments.template, markdown=arguments.markdown );

return builder.renderLinks( rendered );
return builder.renderLinks( rendered, args, arguments.markdown );
} );

StructDelete( arguments.builder, "injectMethod" );
Expand Down
8 changes: 5 additions & 3 deletions api/data/FunctionPage.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ component accessors=true extends="Page" {
return super.getTitle() & "()";
}

public string function getUsageSignature() {
public string function getUsageSignature( boolean plainText=false ) {
var usage = super.getTitle() & "(";
var delim = " ";
var optionalCount = 0;

for( var argument in this.getArguments() ) {
if ( !argument.required ) {
if ( !argument.required && !arguments.plainText ) {
usage &= "<em title='optional'>";
optionalCount++;
}
Expand All @@ -34,7 +34,9 @@ component accessors=true extends="Page" {
} else {
usage &= argument.type;
}
usage &= "</em>";
if ( !argument.required && !arguments.plainText ) {
usage &= "</em>";
}
delim = ", ";
}
//usage &= "</em>";
Expand Down
12 changes: 8 additions & 4 deletions api/data/MethodPage.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ component accessors=true extends="Page" {
property name="member" type="struct";
property name="alias" type="string";

public string function getUsageSignature() {
public string function getUsageSignature( boolean plainText=false ) {
var usage = this.getMethodObject() & "." & this.getMethodName() & "(";
var delim = " ";
var optionalCount = 0;

for( var argument in this.getArguments() ) {
if ( !argument.required ) {
if ( !argument.required && !arguments.plainText ) {
usage &= "<em title='optional'>";
optionalCount++;
}
Expand All @@ -34,10 +34,14 @@ component accessors=true extends="Page" {
} else {
usage &= argument.type;
}
usage &= "</em>";
if ( !argument.required && !arguments.plainText ) {
usage &= "</em>";
}
delim = ", ";
}
usage &= "</em>";
if ( !arguments.plainText ) {
usage &= "</em>";
}
//usage &= RepeatString( " ]", optionalCount );
usage &= " )";

Expand Down
22 changes: 15 additions & 7 deletions api/data/TagPage.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ component accessors=true extends="Page" {
property name="srcExtension" type="struct";
property name="introduced" type="string";

public string function getUsageSignature() {
public string function getUsageSignature( boolean plainText=false ) {
var newLine = Chr(10);
var indent = RepeatString( " ", 4 );
var tagName = "cf" & LCase( this.getName() );
var usage = "&lt;" & tagName;
var usage = ( arguments.plainText ? "<" : "&lt;" ) & tagName;
var closingTag = "";
var bodyType = this.getBodyContentType();
var unnamedAttributes = ( this.getAttributeType() ?: "" ) == "noname";
Expand All @@ -30,7 +30,7 @@ component accessors=true extends="Page" {
usage &= " ###attribute.type# #attribute.name###";
} else {
usage &= newline & indent;
if ( !attribute.required ) {
if ( !attribute.required && !arguments.plainText ) {
usage &= "<em title='optional'>";
}

Expand All @@ -42,7 +42,7 @@ component accessors=true extends="Page" {
usage &= attribute.type;
}

if ( !attribute.required ) {
if ( !attribute.required && !arguments.plainText ) {
usage &= "</em>";
}
}
Expand All @@ -54,13 +54,21 @@ component accessors=true extends="Page" {

switch( bodyType ) {
case "free":
closingTag &= htmlEditFormat("><!--- body --->[</#tagName#>]")
if ( arguments.plainText ) {
closingTag &= "><!--- body ---></#tagName#>";
} else {
closingTag &= htmlEditFormat("><!--- body --->[</#tagName#>]");
}
break;
case "required":
closingTag &= htmlEditFormat("><!--- body ---></#tagName#>")
if ( arguments.plainText ) {
closingTag &= "><!--- body ---></#tagName#>";
} else {
closingTag &= htmlEditFormat("><!--- body ---></#tagName#>");
}
break;
default:
closingTag &= "&gt;";
closingTag &= ( arguments.plainText ? ">" : "&gt;" );
break;
}

Expand Down
69 changes: 69 additions & 0 deletions api/rendering/MarkdownSyntaxHighlighter.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
component {

public string function renderHighlights( required string text ) {
var rendered = arguments.text;
var highlight = "";
var pos = 1;

do {
highlight = _getNextHighlight( rendered, pos );
if ( !IsNull( highlight ) ) {
rendered = Replace( rendered, highlight.rawMatch, renderHighlight( highlight.code, highlight.language ), "all" );
pos = highlight.pos;
}
} while( !IsNull( highlight ) );

return rendered;
}

public string function renderHighlight( required string code, required string language ) {
// Strip +trycf suffix for markdown
var cleanLanguage = arguments.language.reReplace( "\+trycf$", "" );

// Normalize language names for markdown
if ( cleanLanguage.reFindNoCase( "^(luceescript|cfs)" ) ) {
cleanLanguage = "javascript"; // or "js" depending on your markdown renderer
} else if ( cleanLanguage.reFindNoCase( "^(lucee|cfm|coldfusion)" ) ) {
cleanLanguage = "html"; // or "cfml" if supported
} else if ( cleanLanguage eq "yml" ) {
cleanLanguage = "yaml";
}

// Return plain markdown code block
return "```" & cleanLanguage & chr(10) & arguments.code & chr(10) & "```";
}

// PRIVATE HELPERS
private any function _getNextHighlight( required string text, required string startPos=1 ) {
var referenceRegex = "```([a-zA-Z\+]+)?\n(.*?)\n```";
var match = ReFind( referenceRegex, arguments.text, arguments.startPos, true );
var found = match.len[1] > 0;
var result = {};

if ( !found ) {
return;
}

var precedingContent = match.pos[1] == 1 ? "" : Trim( Left( arguments.text, match.pos[1]-1 ) );
var matchIsWithinCodeBlock = precedingContent.endsWith( "<pre>" ) || precedingContent.endsWith( "<code>" );

if ( matchIsWithinCodeBlock ) {
return _getNextHighlight( arguments.text, match.pos[1]+match.len[1] );
}

result = {
rawMatch = Mid( arguments.text, match.pos[1], match.len[1] )
, code = Mid( arguments.text, match.pos[3], match.len[3] )
, pos = match.len[3]
};

if ( match.pos[2] ) {
result.language = Mid( arguments.text, match.pos[2], match.len[2] );
} else {
result.language = "text";
}

return result;
}

}
31 changes: 28 additions & 3 deletions api/rendering/SyntaxHighlighter.cfc
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
component {

public string function renderHighlights( required string text ) {
public string function renderHighlights( required string text, boolean markdown=false ) {
// For markdown mode, strip +trycf and normalize language names
if ( arguments.markdown ) {
var result = arguments.text.reReplace( "```([a-zA-Z]+)\+trycf\n", "```\1" & chr( 10 ), "all" );
// Replace luceescript with cfml for better LLM compatibility
result = result.reReplace( "```luceescript\n", "```cfml" & chr( 10 ), "all" );
result = result.reReplace( "```lucee\n", "```cfml" & chr( 10 ), "all" );
return result;
}

var rendered = arguments.text;
var highlight = "";
var pos = 1;

do {
highlight = _getNextHighlight( rendered, pos );
if ( !IsNull( highlight ) ) {
rendered = Replace( rendered, highlight.rawMatch, renderHighlight( highlight.code, highlight.language ), "all" );
rendered = Replace( rendered, highlight.rawMatch, renderHighlight( highlight.code, highlight.language, arguments.markdown ), "all" );
pos = highlight.pos;
}
} while( !IsNull( highlight ) );

return rendered;
}

public string function renderHighlight( required string code, required string language ) {
public string function renderHighlight( required string code, required string language, boolean markdown=false ) {
// If markdown mode, just clean up the code block and return it as markdown
if ( arguments.markdown ) {
var cleanLanguage = arguments.language.reReplace( "\+trycf$", "" );

// Normalize language names for markdown
if ( cleanLanguage.reFindNoCase( "^(luceescript|cfs)" ) ) {
cleanLanguage = "javascript";
} else if ( cleanLanguage.reFindNoCase( "^(lucee|cfm|coldfusion)" ) ) {
cleanLanguage = "html";
} else if ( cleanLanguage eq "yml" ) {
cleanLanguage = "yaml";
}

return "```" & cleanLanguage & chr( 10 ) & arguments.code & chr( 10 ) & "```";
}

var highlighter = new Pygments();
var useTryCf = reFind( "\+trycf$", arguments.language ) > 0;

Expand Down
4 changes: 2 additions & 2 deletions api/rendering/TemplateRenderer.cfc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
component {

public string function render( required string template, struct args={}, string helpers="" ) {
public string function render( required string template, struct args={}, string helpers="", boolean markdown=false ) {
var rendered = "";

_includeHelpers( arguments.helpers );
Expand All @@ -9,7 +9,7 @@ component {
include template=arguments.template;
}

rendered = new SyntaxHighlighter().renderHighlights( rendered );
rendered = new SyntaxHighlighter().renderHighlights( rendered, arguments.markdown );

return Trim( rendered );
}
Expand Down
5 changes: 3 additions & 2 deletions api/rendering/WikiLinksRenderer.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ component accessors=true {

property name="docTree";

public string function renderLinks( required string text, required any builder ) {
public string function renderLinks( required string text, required any builder, required struct args, boolean markdown=false ) {
var rendered = arguments.text;
var link = "";
var startPos = 1;
Expand All @@ -14,7 +14,8 @@ component accessors=true {
rendered = Replace( rendered, link.rawMatch, content, "one" );
//startPos = link.nextStartPos + len( content );
} else {
rendered = Replace( rendered, link.rawMatch, arguments.builder.renderLink( link.page ?: NullValue(), link.title ), "all" );
rendered = Replace( rendered, link.rawMatch,
arguments.builder.renderLink( link.page ?: NullValue(), link.title, args, arguments.markdown ), "all" );
startPos = link.nextStartPos;
}
}
Expand Down
Loading