diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2020-10-30 18:40:32 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-30 18:40:32 -0600 |
| commit | ca2ca428aacfcde709db739bc3cf94beb21b7692 (patch) | |
| tree | b454716be790f3750bb250bc47ab791cdbd6c951 | |
| parent | b765ec86a6367d871d8ac4e223ecb4dced18d975 (diff) | |
resolves #3760 apply text formatting to table cells in header row when column has a or l style (PR #3790)
| -rw-r--r-- | CHANGELOG.adoc | 1 | ||||
| -rw-r--r-- | lib/asciidoctor/parser.rb | 20 | ||||
| -rw-r--r-- | lib/asciidoctor/table.rb | 51 | ||||
| -rw-r--r-- | test/tables_test.rb | 129 |
4 files changed, 180 insertions, 21 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 6f08f0ed..e110f8a9 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -19,6 +19,7 @@ Bug Fixes:: * Fix infinite loop when callout list with obsolete syntax is found inside list item (#3472) * Fix infinite loop when xreftext contains a circular reference path in HTML and manpage converters (#3543) + * Apply text formatting to table cells in implicit header row when column has the "a" or "l" style (#3760) * Fix errant reference warning for valid reference when running in compat mode (#3555) * Initialize backend traits for converter (if not previously initialized) using assigned basebackend; mimics Asciidoctor < 2 behavior (#3341) * Set source_location on preamble block when sourcemap option is enabled (#3799) diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb index 29bfa06c..efc5557f 100644 --- a/lib/asciidoctor/parser.rb +++ b/lib/asciidoctor/parser.rb @@ -2281,7 +2281,8 @@ class Parser if attributes['header-option'] table.has_header_option = true elsif skipped == 0 && !attributes['noheader-option'] - implicit_header = true + # NOTE: assume table has header until we know otherwise; if it doesn't (nil), cells in first row get reprocessed + table.has_header_option = implicit_header = true end parser_ctx = Table::ParserContext.new table_reader, table, attributes format, loop_idx, implicit_header_boundary = parser_ctx.format, -1, nil @@ -2304,7 +2305,7 @@ class Parser implicit_header_boundary = nil if implicit_header_boundary # otherwise, the cell continues from previous line elsif implicit_header_boundary && implicit_header_boundary == loop_idx - implicit_header, implicit_header_boundary = false, nil + table.has_header_option = implicit_header = implicit_header_boundary = nil end end end @@ -2316,7 +2317,7 @@ class Parser if table_reader.has_more_lines? && table_reader.peek_line.empty? implicit_header_boundary = 1 else - implicit_header = false + table.has_header_option = implicit_header = nil end end end @@ -2367,7 +2368,7 @@ class Parser case format when 'csv' if parser_ctx.buffer_has_unclosed_quotes? - implicit_header, implicit_header_boundary = false, nil if implicit_header_boundary && loop_idx == 0 + table.has_header_option = implicit_header = implicit_header_boundary = nil if implicit_header_boundary && loop_idx == 0 parser_ctx.keep_cell_open else parser_ctx.close_cell true @@ -2389,15 +2390,8 @@ class Parser end end - unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_colspecs - table.assign_column_widths - end - - if implicit_header - table.has_header_option = true - attributes['header-option'] = '' - end - + table.assign_column_widths unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_colspecs + attributes['header-option'] = '' if implicit_header table.partition_header_footer attributes table diff --git a/lib/asciidoctor/table.rb b/lib/asciidoctor/table.rb index c8cce9bd..e7f202b1 100644 --- a/lib/asciidoctor/table.rb +++ b/lib/asciidoctor/table.rb @@ -156,11 +156,14 @@ class Table < AbstractBlock # set rowcount before splitting up body rows num_body_rows = @attributes['rowcount'] = (body = @rows.body).size - if num_body_rows > 0 && @has_header_option - @rows.head = [(head = body.shift)] - # styles aren't applied to header row - head.each {|c| c.style = nil } - num_body_rows -= 1 + if num_body_rows > 0 + if @has_header_option + @rows.head = [body.shift.map {|cell| cell.reinitialize true }] + num_body_rows -= 1 + elsif @has_header_option.nil? + @has_header_option = false + body.unshift(body.shift.map {|cell| cell.reinitialize false }) + end end @rows.foot = [body.pop] if num_body_rows > 0 && attrs['footer-option'] @@ -231,9 +234,18 @@ class Table::Cell < AbstractBlock def initialize column, cell_text, attributes = {}, opts = {} super column, :table_cell + @cursor = @reinitialize_args = nil @source_location = opts[:cursor].dup if @document.sourcemap + # NOTE: column is always set when parsing; may not be set when building table from the API if column - cell_style = column.style unless (in_header_row = column.table.header_row?) + if (in_header_row = column.table.header_row?) + if (cell_style = column.style || attributes&.[]('style')) == :asciidoc || cell_style == :literal + @reinitialize_args = [column, cell_text, attributes&.merge, opts] + end + cell_style = nil + else + cell_style = column.style + end # REVIEW feels hacky to inherit all attributes from column update_attributes column.attributes end @@ -300,8 +312,12 @@ class Table::Cell < AbstractBlock @content_model = :verbatim @subs = BASIC_SUBS else - if normal_psv && (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text - Parser.catalog_inline_anchor $1, $2, self, opts[:cursor], @document + if normal_psv + if in_header_row + @cursor = opts[:cursor] # used in deferred catalog_inline_anchor call + else + catalog_inline_anchor cell_text, opts[:cursor] + end end @content_model = :simple @subs = NORMAL_SUBS @@ -310,6 +326,25 @@ class Table::Cell < AbstractBlock @style = cell_style end + def reinitialize has_header + if has_header + @reinitialize_args = nil + elsif @reinitialize_args + return Table::Cell.new(*@reinitialize_args) + else + @style = @attributes['style'] + end + catalog_inline_anchor if @cursor + self + end + + def catalog_inline_anchor cell_text = @text, cursor = nil + cursor, @cursor = @cursor, nil unless cursor + if (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text + Parser.catalog_inline_anchor $1, $2, self, cursor, @document + end + end + # Public: Get the String text of this cell with substitutions applied. # # Used for cells in the head row as well as text-only (non-AsciiDoc) cells in diff --git a/test/tables_test.rb b/test/tables_test.rb index 3afab5e3..61ede120 100644 --- a/test/tables_test.rb +++ b/test/tables_test.rb @@ -791,6 +791,63 @@ context 'Tables' do assert_xpath '(//td)[1]/p', output, 2 end + test 'should format first cell as literal if there is no implicit header row and column has l style' do + input = <<~'EOS' + [cols="1l,1"] + |=== + |literal + |normal + |=== + EOS + + output = convert_string_to_embedded input + assert_css 'tbody pre', output, 1 + assert_css 'tbody p.tableblock', output, 1 + end + + test 'wip should format first cell as AsciiDoc if there is no implicit header row and column has a style' do + input = <<~'EOS' + [cols="1a,1"] + |=== + | * list + | normal + |=== + EOS + + output = convert_string_to_embedded input + assert_css 'tbody .ulist', output, 1 + assert_css 'tbody p.tableblock', output, 1 + end + + test 'should interpret leading indent if first cell is AsciiDoc and there is no implicit header row' do + # NOTE cannot use single-quoted heredoc because of https://github.com/jruby/jruby/issues/4260 + input = <<~EOS + [cols="1a,1"] + |=== + | + literal + | normal + |=== + EOS + + output = convert_string_to_embedded input + assert_css 'tbody pre', output, 1 + assert_css 'tbody p.tableblock', output, 1 + end + + test 'should format first cell as AsciiDoc if there is no implicit header row and cell has a style' do + input = <<~'EOS' + |=== + a| * list + | normal + |=== + EOS + + output = convert_string_to_embedded input + assert_css 'tbody .ulist', output, 1 + assert_css 'tbody p.tableblock', output, 1 + end + test 'no implicit header row if AsciiDoc cell in first line spans multiple lines' do input = <<~'EOS' [cols=2*] @@ -885,6 +942,39 @@ context 'Tables' do assert_css 'table > tbody > tr > td > p > em > a', output, 1 end + test 'should apply text formatting to cells in implicit header row when column has a style' do + input = <<~'EOS' + [cols="2*a"] + |=== + | _foo_ | *bar* + + | * list item + | paragraph + |=== + EOS + output = convert_string_to_embedded input + assert_xpath '(//thead/tr/th)[1]/em[text()="foo"]', output, 1 + assert_xpath '(//thead/tr/th)[2]/strong[text()="bar"]', output, 1 + assert_css 'tbody .ulist', output, 1 + assert_css 'tbody .paragraph', output, 1 + end + + test 'should apply style and text formatting to cells in first row if no implicit header' do + input = <<~'EOS' + [cols="s,e"] + |=== + | _strong_ | *emphasis* + | strong + | emphasis + |=== + EOS + output = convert_string_to_embedded input + assert_xpath '((//tbody/tr)[1]/td)[1]//strong/em[text()="strong"]', output, 1 + assert_xpath '((//tbody/tr)[1]/td)[2]//em/strong[text()="emphasis"]', output, 1 + assert_xpath '((//tbody/tr)[2]/td)[1]//strong[text()="strong"]', output, 1 + assert_xpath '((//tbody/tr)[2]/td)[2]//em[text()="emphasis"]', output, 1 + end + test 'vertical table headers use th element instead of header class' do input = <<~'EOS' [cols="1h,1s,1e"] @@ -1430,6 +1520,45 @@ context 'Tables' do assert_xpath '(//table/tbody/tr)[2]//th//a[@id="grays-peak"]', output, 1 end + test 'should catalog anchor at start of cell in implicit header row when column has a style' do + input = <<~'EOS' + [cols=1a] + |=== + |[[foo,Foo]]* not AsciiDoc + + | AsciiDoc + |=== + EOS + doc = document_from_string input + refs = doc.catalog[:refs] + assert refs.key?('foo') + end + + test 'should catalog anchor at start of cell in explicit header row when column has a style' do + input = <<~'EOS' + [%header,cols=1a] + |=== + |[[foo,Foo]]* not AsciiDoc + | AsciiDoc + |=== + EOS + doc = document_from_string input + refs = doc.catalog[:refs] + assert refs.key?('foo') + end + + test 'should catalog anchor at start of cell in first row' do + input = <<~'EOS' + |=== + |[[foo,Foo]]foo + | bar + |=== + EOS + doc = document_from_string input + refs = doc.catalog[:refs] + assert refs.key?('foo') + end + test 'footnotes should not be shared between an AsciiDoc table cell and the main document' do input = <<~'EOS' |=== |
