diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst index f8098c83af..f03f01d3d4 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst @@ -89,6 +89,11 @@ The filters are chained and apply from left to right. filter[, filter]* +Any part of a query may be commented out using a ``/* ... */`` block comment. +This lets you temporarily disable part of a query without deleting the text, for +example ``IfcWall + /* IfcSlab, material=concrete */`` selects only walls while +keeping the slab criteria on hand. Block comments may span multiple lines. + Below is the table of filters to choose from. Most of these filters will filter previously added elements in your filter group based on their criteria. diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 32f3b632c0..51b2411368 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -41,7 +41,7 @@ import ifcopenshell.util.unit filter_elements_grammar = lark.Lark( """start: filter_group - filter_group: facet_list ("+" facet_list)* + filter_group: facet_list ("+" facet_list)* "+"? facet_list: facet ("," facet)* facet: instance | entity | attribute | type | material | query | classification | location | property | group | parent @@ -109,8 +109,10 @@ filter_elements_grammar = lark.Lark( CR : /\\r/ LF : /\\n/ NEWLINE: (CR? LF)+ + COMMENT: "/*" /.*?/s "*/" %ignore WS // Disregard spaces in text + %ignore COMMENT // Allow /* ... */ block comments to toggle parts of a query """ ) diff --git a/src/ifcopenshell-python/test/util/test_selector.py b/src/ifcopenshell-python/test/util/test_selector.py index b8302e0f4a..3319e0df7a 100644 --- a/src/ifcopenshell-python/test/util/test_selector.py +++ b/src/ifcopenshell-python/test/util/test_selector.py @@ -351,6 +351,22 @@ class TestFilterElements(test.bootstrap.IFC4): assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab") == {element, element2} assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab, Name=Bar") == {element, element2} + def test_block_comments_are_ignored(self): + element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall") + element.Name = "Foo" + element2 = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcSlab") + element2.Name = "Bar" + # A /* ... */ block comment lets a query be toggled off without deleting the text. + assert subject.filter_elements(self.file, "IfcWall /* + IfcSlab */") == {element} + assert subject.filter_elements(self.file, "IfcWall + /* IfcSlab */") == {element} + assert subject.filter_elements(self.file, "/* IfcWall + */ IfcSlab") == {element2} + assert subject.filter_elements(self.file, "IfcWall /* commented */ + IfcSlab") == {element, element2} + # Comments may span multiple lines. + assert subject.filter_elements(self.file, "IfcWall + /* multi\nline\ncomment */ IfcSlab") == {element, element2} + # A /* sequence inside a quoted string is not treated as a comment. + element.Name = "a/*b" + assert subject.filter_elements(self.file, 'IfcWall, Name="a/*b"') == {element} + def test_using_elements_argument(self): wall = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall") slab = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcSlab")