summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2020-10-30 18:40:32 -0600
committerGitHub <noreply@github.com>2020-10-30 18:40:32 -0600
commitca2ca428aacfcde709db739bc3cf94beb21b7692 (patch)
treeb454716be790f3750bb250bc47ab791cdbd6c951
parentb765ec86a6367d871d8ac4e223ecb4dced18d975 (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.adoc1
-rw-r--r--lib/asciidoctor/parser.rb20
-rw-r--r--lib/asciidoctor/table.rb51
-rw-r--r--test/tables_test.rb129
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'
|===