Skip to content

Commit

Permalink
resolves asciidoctor#185 autofit font size in listing & literal blocks
Browse files Browse the repository at this point in the history
- reduce font size to prevent wrapping in listing & literal blocks
- activate if autofit option is specified on block
- activate if autofit-option attribute is specified on document
  • Loading branch information
mojavelinux committed Jun 12, 2015
1 parent b27e700 commit 508ba10
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
39 changes: 35 additions & 4 deletions lib/asciidoctor-pdf/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,8 @@ def convert_image node
unlink_tmp_file image_path
end

# TODO shrink text if it's too wide to fit in the bounding box
def convert_listing_or_literal node
autofit = (node.option? 'autofit') || (node.document.attr? 'autofit-option')
add_dest_for_block node if node.id
# HACK disable built-in syntax highlighter; must be done before calling node.content!
# NOTE the highlight sub is only set for coderay and pygments
Expand All @@ -861,16 +861,18 @@ def convert_listing_or_literal node
highlighter = nil
prev_subs = nil
end
# FIXME source highlighter freaks out about the non-breaking space characters; does it?
source_string = preserve_indentation node.content
longest_line = nil
source_chunks = case highlighter
when 'coderay'
Helpers.require_library CodeRayRequirePath, 'coderay' unless defined? ::Asciidoctor::Prawn::CodeRayEncoder
longest_line = source_string.split(EOL).max_by &:length if autofit
source_string, conum_mapping = extract_conums source_string
fragments = (::CodeRay.scan source_string, (node.attr 'language', 'text', false).to_sym).to_prawn
conum_mapping ? (restore_conums fragments, conum_mapping) : fragments
when 'pygments'
Helpers.require_library 'pygments', 'pygments.rb' unless defined? ::Pygments
longest_line = source_string.split(EOL).max_by &:length if autofit
source_string, conum_mapping = extract_conums source_string
lexer = ::Pygments::Lexer[node.attr 'language', 'text', false] || ::Pygments::Lexer['text']
pygments_config = { nowrap: true, noclasses: true, style: (node.document.attr 'pygments-style') || 'pastie' }
Expand All @@ -879,14 +881,23 @@ def convert_listing_or_literal node
conum_mapping ? (restore_conums fragments, conum_mapping) : fragments
else
# NOTE only format if we detect a need
(source_string =~ BuiltInEntityCharOrTagRx) ? (text_formatter.format source_string) : [{ text: source_string }]
if source_string =~ BuiltInEntityCharOrTagRx
longest_line = source_string.split(EOL).map {|l| unescape_builtin l }.max_by &:length if autofit
text_formatter.format source_string
else
longest_line = source_string.split(EOL).max_by &:length if autofit
[{ text: source_string }]
end
end

node.subs.replace prev_subs if prev_subs

#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top

# FIXME this calculation may overcompensate if callout numbers or inline formatting are present in line
adjusted_font_size = autofit ? (theme_font_size_autofit longest_line, :code) : nil

keep_together do |box_height = nil|
caption_height = node.title? ? (layout_caption node) : 0
theme_font :code do
Expand All @@ -909,7 +920,7 @@ def convert_listing_or_literal node
end

pad_box @theme.code_padding do
typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height), color: (@theme.code_font_color || @font_color)
typeset_formatted_text source_chunks, (calc_line_metrics @theme.code_line_height), color: (@theme.code_font_color || @font_color), size: adjusted_font_size
end
end
end
Expand Down Expand Up @@ -1985,6 +1996,26 @@ def theme_font category, opts = {}
@text_transform = prev_transform if transform
end

def theme_font_size_autofit line, category
adjusted_font_size = nil
if (padding = @theme[%(#{category}_padding)])
_, p_right, _, p_left = (::Array === padding) ? padding : ([padding] * 4)
else
p_right = p_left = 0
end
theme_font category do
indent p_left, p_right do
if (actual_width = width_of line) > (available_width = bounds.width)
# this calculation works if we assume code is monospaced
adjusted_font_size = (((available_width * font_size).to_f / actual_width) * 1000.0).floor / 1000.0
else
adjusted_font_size = font_size
end
end
end
adjusted_font_size
end

# TODO document me, esp the first line formatting functionality
def typeset_text string, line_metrics, opts = {}
move_down line_metrics.padding_top
Expand Down
10 changes: 10 additions & 0 deletions lib/asciidoctor-pdf/sanitizer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ def sanitize string
.gsub(BuiltInEntityCharRx, BuiltInEntityChars)
end

def unescape_all string
string
.gsub(NumericCharRefRx) { [$1.to_i].pack('U*') }
.gsub(BuiltInEntityCharRx, BuiltInEntityChars)
end

def unescape_builtin string
string.gsub(BuiltInEntityCharRx, BuiltInEntityChars)
end

def upcase_pcdata string
if BuiltInEntityCharOrTagRx =~ string
string.gsub(SegmentPcdataRx) { $2 ? $2.upcase : $1 }
Expand Down

0 comments on commit 508ba10

Please sign in to comment.