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
51 changes: 37 additions & 14 deletions lib/utopia/project/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,30 +174,53 @@ def code_node(content, language = nil)

private

# Replace source code references in the given text with HTML anchors.
# Resolve a source code reference to HTML.
# @parameter content [String] The source code reference.
# @parameter language [String | Nil] The explicit source language.
# @returns [Markly::Node] The resolved link or code node.
# @returns [Markly::Node] The inline HTML node.
def reference_node(content, language: nil)
reference, definition = resolve_reference(content, language: language)

if definition
content = definition.qualified_form
language = reference.language.name
elsif reference
content = reference.identifier
language = reference.language.name
end

attributes = {}
attributes[:class] = "language-#{language}" if language

markup = XRB::Builder.fragment do |builder|
builder.inline("code", attributes) do
if definition
builder.inline("a", href: @base.link_for(definition), title: reference.identifier) do
builder.text(content)
end
else
builder.text(content)
end
end
end

return inline_html_node(markup.to_s)
end

# Resolve source code reference metadata and its indexed definition.
# @parameter content [String] The source code reference.
# @parameter language [String | Nil] The explicit source language.
# @returns [Array] The parsed reference and resolved definition.
def resolve_reference(content, language: nil)
reference = if language
@index.languages.reference_for(language, content)
else
@index.languages.parse_reference(content, default_language: @default_language)
end

if reference
definition = @index.lookup(reference, relative_to: @definition)
end
definition = @index.lookup(reference, relative_to: @definition) if reference

if definition
link_node(reference.identifier, @base.link_for(definition),
code_node(definition.qualified_form, reference.language.name)
)
elsif reference
code_node(reference.identifier, reference.language.name)
else
code_node(content, language)
end
return reference, definition
end

def resolve(root)
Expand Down
12 changes: 3 additions & 9 deletions lib/utopia/project/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ module Project
# Renders project Markdown with support for Mermaid code blocks.
class Renderer < Markly::Renderer::HTML
# Initialize the project renderer.
# @parameter inline_code_resolver [Proc | Nil] Resolves language-prefixed inline code into a replacement node.
# @parameter inline_code_resolver [Proc | Nil] Resolves language-prefixed inline code into an inline HTML node.
def initialize(inline_code_resolver: nil, **options)
@inline_code_resolver = inline_code_resolver
@resolving_inline_code = false

super(**options)
end
Expand Down Expand Up @@ -58,13 +57,8 @@ def code_block(node)
# Render inline code, resolving language-prefixed references when possible.
# @parameter node [Markly::Node] The inline code node.
def code(node)
if @inline_code_resolver && !@resolving_inline_code && (language = node.code_language)
begin
@resolving_inline_code = true
out(@inline_code_resolver.call(node.string_content, language: language))
ensure
@resolving_inline_code = false
end
if @inline_code_resolver && (language = node.code_language)
out(@inline_code_resolver.call(node.string_content, language: language))
else
super
end
Expand Down
4 changes: 4 additions & 0 deletions releases.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changes

## Unreleased

- Render resolved inline code references with links inside their code elements so hover and keyboard focus affect the complete reference.

## v0.44.0

- Add support for language-prefixed inline code references such as ruby:`Object.new`.
Expand Down
16 changes: 13 additions & 3 deletions test/utopia/project/document.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@
expect(document.to_markdown).to be == "Use ruby:`Object.new` to create an object.\n"
end

it "escapes language-prefixed inline code" do
root = File.expand_path("../../..", __dir__)
base = Utopia::Project::Base.new(root)
document = subject.new("Compare ruby:`foo < bar`.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<code class="language-ruby">foo &lt; bar</code>')
end

it "resolves language-prefixed inline code references" do
root = File.expand_path("../../..", __dir__)
base = Utopia::Project::Base.new(root)
Expand All @@ -41,8 +50,8 @@
document = subject.new("See ruby:`Utopia::Project::Document#root`.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
expect(html).to be(:include?, '<code class="language-ruby">Utopia::Project::Document#root</code>')
expect(html).to be(:include?, '<code class="language-ruby"><a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
expect(html).to be(:include?, ">Utopia::Project::Document#root</a></code>")
end

it "continues to resolve legacy brace references" do
Expand All @@ -53,7 +62,8 @@
document = subject.new("See {ruby Utopia::Project::Document#root}.", base)
html = document.to_html.to_s

expect(html).to be(:include?, '<a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
expect(html).to be(:include?, '<code class="language-ruby"><a href="/reference/Utopia/Project/Document/index#Utopia%3A%3AProject%3A%3ADocument%23root"')
expect(html.scan("<a ").size).to be == 1
end

it "can replace usage" do
Expand Down
Loading