From b669438c02d1e33067c7f9a4d8048b6a894034ae Mon Sep 17 00:00:00 2001 From: Robert Panzer Date: Sun, 31 Mar 2024 10:35:40 +0200 Subject: [PATCH] Fixes #1265. Support setting column widths (#1270) * Fixes #1265. Support setting column widths * Fix test for upstream * Add test for autowidth columns * Update changelog --- CHANGELOG.adoc | 1 + .../main/java/org/asciidoctor/ast/Table.java | 1 + .../asciidoctor/jruby/ast/impl/TableImpl.java | 21 +++++ .../GithubContributorsBlockMacro.groovy | 13 +++- ...enABlockMacroProcessorCreatesATable.groovy | 76 +++++++++++++++++-- config/codenarc/codenarc.groovy | 4 +- 6 files changed, 109 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 835069e12..7967b3478 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -32,6 +32,7 @@ Improvement:: Bug Fixes:: * -s CLI option should be changed to -e to align with Asciidoctor (#1237) (@mojavelinux) +* Column#setWidth is ignored (#1265) (@Vampire) === Compatible changes diff --git a/asciidoctorj-api/src/main/java/org/asciidoctor/ast/Table.java b/asciidoctorj-api/src/main/java/org/asciidoctor/ast/Table.java index b4dfae0f8..c3c167ecc 100644 --- a/asciidoctorj-api/src/main/java/org/asciidoctor/ast/Table.java +++ b/asciidoctorj-api/src/main/java/org/asciidoctor/ast/Table.java @@ -57,4 +57,5 @@ enum VerticalAlignment { */ void setGrid(String grid); + void assignColumnWidths(); } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/ast/impl/TableImpl.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/ast/impl/TableImpl.java index f5b269ed3..5cc94f31d 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/ast/impl/TableImpl.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/ast/impl/TableImpl.java @@ -7,6 +7,7 @@ import org.asciidoctor.jruby.internal.RubyObjectWrapper; import org.jruby.RubyArray; import org.jruby.RubyNil; +import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import java.util.AbstractList; @@ -72,6 +73,26 @@ public List getHeader() { return rows.getHeader(); } + @Override + public void assignColumnWidths() { + int widthBase = 0; + RubyArray autowidthCols = getRuntime().newArray(); + for (Column column : getColumns()) { + int width = column.getWidth(); + if (width < 0) { + autowidthCols.add(((ColumnImpl)column).getRubyObject()); + } else { + widthBase += width; + } + } + ThreadContext threadContext = getRuntime().getThreadService().getCurrentContext(); + + getRubyObject().callMethod(threadContext, "assign_column_widths", new IRubyObject[] { + getRuntime().newFixnum(widthBase), + autowidthCols.isEmpty() ? getRuntime().getNil() : autowidthCols + }); + } + private class Rows extends RubyObjectWrapper { public Rows(IRubyObject rubyNode) { diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/GithubContributorsBlockMacro.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/GithubContributorsBlockMacro.groovy index 75ff2a427..106169283 100644 --- a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/GithubContributorsBlockMacro.groovy +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/GithubContributorsBlockMacro.groovy @@ -12,6 +12,7 @@ import org.asciidoctor.util.TestHttpServer class GithubContributorsBlockMacro extends BlockMacroProcessor { private static final String IMAGE = 'image' + private static final String WIDTHS = 'widths' GithubContributorsBlockMacro(String macroName) { super(macroName) @@ -29,12 +30,22 @@ class GithubContributorsBlockMacro extends BlockMacroProcessor { table.grid = 'rows' table.title = "Github contributors of $target" + List widths = [1,2,2] + if (attributes.containsKey(WIDTHS)) { + widths = (attributes[WIDTHS] as String).split(',').collect {Integer.parseInt(it) } + } // Create the columns 'Login' and 'Contributions' Column avatarColumn = createTableColumn(table, 0) + avatarColumn.width = widths[0] Column loginColumn = createTableColumn(table, 1) + loginColumn.width = widths[1] Column contributionsColumn = createTableColumn(table, 2) + contributionsColumn.width = widths[2] contributionsColumn.horizontalAlignment = Table.HorizontalAlignment.CENTER - + table.columns << avatarColumn + table.columns << loginColumn + table.columns << contributionsColumn + table.assignColumnWidths() // Create the single header row with the column titles Row headerRow = createTableRow(table) headerRow.cells << createTableCell(avatarColumn, 'Avatar') diff --git a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenABlockMacroProcessorCreatesATable.groovy b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenABlockMacroProcessorCreatesATable.groovy index ff694bfed..c3c46eb97 100644 --- a/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenABlockMacroProcessorCreatesATable.groovy +++ b/asciidoctorj-core/src/test/groovy/org/asciidoctor/extension/WhenABlockMacroProcessorCreatesATable.groovy @@ -7,19 +7,35 @@ import org.asciidoctor.test.extension.ClasspathHelper import org.asciidoctor.util.TestHttpServer import org.jsoup.Jsoup import org.jsoup.nodes.Document +import org.jsoup.select.Elements import spock.lang.Specification import spock.lang.TempDir +import static java.nio.charset.StandardCharsets.UTF_8 + class WhenABlockMacroProcessorCreatesATable extends Specification { public static final String FIRST_TD = 'td:first-child' public static final String SECOND_TD = 'td:nth-child(2)' public static final String THIRD_TD = 'td:nth-child(3)' public static final String IMG_ELEMENT = 'img' + public static final String COL = 'col' + public static final String STYLE = 'style' + public static final String WIDTH = 'width' + public static final String WIDTH_2 = '2%' + public static final String WIDTH_3 = '3%' + public static final String WIDTH_20 = '20%' + public static final String WIDTH_40 = '40%' public static final String CONTRIBUTOR = 'bob' public static final String BLOCKMACRO_NAME = 'githubcontributors' public static final String AVATAR_URL_REGEXP = /https:\/\/avatars.githubusercontent.com\/u\/.*/ + public static final String CSS_QUERY_TABLE = 'table' + public static final String CLASS_GRID_ROWS = 'grid-rows' + public static final String CLASS_HALIGN_LEFT = 'halign-left' + public static final String CLASS_HALIGN_CENTER = 'halign-center' + public static final String ATTR_SRC = 'src' + public static final int THREE = 3 private Asciidoctor asciidoctor @@ -30,6 +46,12 @@ class WhenABlockMacroProcessorCreatesATable extends Specification { = AsciidoctorJRuby contributors githubcontributors::asciidoctor/asciidoctorj[] +''' + + private static final String DOCUMENT_WITH_NEGATIVE_WIDTHS = ''' += AsciidoctorJRuby contributors + +githubcontributors::asciidoctor/asciidoctorj[widths="2,3,-1"] ''' private ClasspathHelper classpathResources @@ -60,18 +82,62 @@ githubcontributors::asciidoctor/asciidoctorj[] asciidoctor.convert(DOCUMENT, options) then: - Document htmlDocument = Jsoup.parse(resultFile, 'UTF-8') + Document htmlDocument = Jsoup.parse(resultFile, UTF_8.name()) + + Elements cols = htmlDocument.select(COL) + cols.size() == THREE + cols.get(0).attr(STYLE).contains(WIDTH_20) || cols.get(0).attr(WIDTH).equals(WIDTH_20) + cols.get(1).attr(STYLE).contains(WIDTH_40) || cols.get(1).attr(WIDTH).equals(WIDTH_40) + cols.get(2).attr(STYLE).contains(WIDTH_40) || cols.get(2).attr(WIDTH).equals(WIDTH_40) + + htmlDocument.select(CSS_QUERY_TABLE).hasClass(CLASS_GRID_ROWS) + + htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT).size() == 1 } + htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr(ATTR_SRC) =~ AVATAR_URL_REGEXP } + + htmlDocument.select(SECOND_TD).size() == htmlDocument.select(SECOND_TD) != 0 + htmlDocument.select(SECOND_TD).size() != 0 + + htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_LEFT) } + htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_CENTER) } + + htmlDocument.select(SECOND_TD).find { tdElement -> tdElement.text() == CONTRIBUTOR } != null + } + + def "the table should be rendered to html with negative widths"() { + given: + asciidoctor.javaExtensionRegistry().blockMacro(BLOCKMACRO_NAME, GithubContributorsBlockMacro) + File resultFile = new File(tempDir, 'resultWithNegativeWidth.html') + + when: + def options = Options.builder() + .safe(SafeMode.SAFE) + .inPlace(false) + .baseDir(tempDir) + .toDir(tempDir) + .toFile(resultFile) + .build() + asciidoctor.convert(DOCUMENT_WITH_NEGATIVE_WIDTHS, options) + + then: + Document htmlDocument = Jsoup.parse(resultFile, UTF_8.name()) + + Elements cols = htmlDocument.select(COL) + cols.size() == THREE + cols.get(0).attr(STYLE).contains(WIDTH_2) || cols.get(0).attr(WIDTH).equals(WIDTH_2) + cols.get(1).attr(STYLE).contains(WIDTH_3) || cols.get(1).attr(WIDTH).equals(WIDTH_3) + cols.get(2).attr(STYLE).length() == 0 && cols.get(2).attr(WIDTH).length() == 0 - htmlDocument.select('table').hasClass('grid-rows') + htmlDocument.select(CSS_QUERY_TABLE).hasClass(CLASS_GRID_ROWS) htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT).size() == 1 } - htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr('src') =~ AVATAR_URL_REGEXP } + htmlDocument.select(FIRST_TD).every { tdElement -> tdElement.select(IMG_ELEMENT)[0].attr(ATTR_SRC) =~ AVATAR_URL_REGEXP } htmlDocument.select(SECOND_TD).size() == htmlDocument.select(SECOND_TD) != 0 htmlDocument.select(SECOND_TD).size() != 0 - htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass('halign-left') } - htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass('halign-center') } + htmlDocument.select(SECOND_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_LEFT) } + htmlDocument.select(THIRD_TD).every { tdElement -> tdElement.hasClass(CLASS_HALIGN_CENTER) } htmlDocument.select(SECOND_TD).find { tdElement -> tdElement.text() == CONTRIBUTOR } != null } diff --git a/config/codenarc/codenarc.groovy b/config/codenarc/codenarc.groovy index 7c5a5b5fc..6f7d308c6 100644 --- a/config/codenarc/codenarc.groovy +++ b/config/codenarc/codenarc.groovy @@ -43,7 +43,9 @@ ruleset { ruleset('rulesets/braces.xml') { exclude 'IfStatementBraces' } - ruleset('rulesets/size.xml') + ruleset('rulesets/size.xml') { + exclude 'AbcMetric' + } ruleset('rulesets/junit.xml') { // Does not play well with Spock tests exclude 'JUnitPublicNonTestMethod'