1da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# 2da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# Copyright (C) 2012 The Android Open Source Project 3da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# 4da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# Licensed under the Apache License, Version 2.0 (the "License"); 5da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# you may not use this file except in compliance with the License. 6da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# You may obtain a copy of the License at 7da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# 8da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# http://www.apache.org/licenses/LICENSE-2.0 9da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# 10da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# Unless required by applicable law or agreed to in writing, software 11da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# distributed under the License is distributed on an "AS IS" BASIS, 12da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# See the License for the specific language governing permissions and 14da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# limitations under the License. 15da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# 16da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 17da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin""" 18da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor MurashkinA set of helpers for rendering Mako templates with a Metadata model. 19da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin""" 20da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 21da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkinimport metadata_model 22aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkinimport re 238aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkinimport markdown 248aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkinimport textwrap 2563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvalaimport sys 260b080452cca90f215d10d636abfb47701d7518daIgor Murashkinimport bs4 270b080452cca90f215d10d636abfb47701d7518daIgor Murashkin# Monkey-patch BS4. WBR element must not have an end tag. 280b080452cca90f215d10d636abfb47701d7518daIgor Murashkinbs4.builder.HTMLTreeBuilder.empty_element_tags.add("wbr") 298aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 30586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkinfrom collections import OrderedDict 31da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 321dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin# Relative path from HTML file to the base directory used by <img> tags 331dd4ecb0ea0589610b3616459b707c2898889153Igor MurashkinIMAGE_SRC_METADATA="images/camera2/metadata/" 341dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 351dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin# Prepend this path to each <img src="foo"> in javadocs 361dd4ecb0ea0589610b3616459b707c2898889153Igor MurashkinJAVADOC_IMAGE_SRC_METADATA="../../../../" + IMAGE_SRC_METADATA 37c9c2c6849c68ddb458d63b5f864ea76a8448a3d2Yin-Chia YehNDKDOC_IMAGE_SRC_METADATA="../" + IMAGE_SRC_METADATA 381dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 39da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin_context_buf = None 40da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 41da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef _is_sec_or_ins(x): 42da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return isinstance(x, metadata_model.Section) or \ 43da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin isinstance(x, metadata_model.InnerNamespace) 44da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 45da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## 46da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## Metadata Helpers 47da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## 48da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 49da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef find_all_sections(root): 50da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 51da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Find all descendants that are Section or InnerNamespace instances. 52da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 53da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 54da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin root: a Metadata instance 55da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 56da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 57da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A list of Section/InnerNamespace instances 58da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 59da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Remarks: 60da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin These are known as "sections" in the generated C code. 61da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 62da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return root.find_all(_is_sec_or_ins) 63da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 64da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef find_parent_section(entry): 65da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 66da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Find the closest ancestor that is either a Section or InnerNamespace. 67da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 68da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 69da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin entry: an Entry or Clone node 70da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 71da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 72da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin An instance of Section or InnerNamespace 73da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 74da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return entry.find_parent_first(_is_sec_or_ins) 75da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 76da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# find uniquely named entries (w/o recursing through inner namespaces) 77da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef find_unique_entries(node): 78da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 79da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Find all uniquely named entries, without recursing through inner namespaces. 80da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 81da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 82da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin node: a Section or InnerNamespace instance 83da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 84da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Yields: 85da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A sequence of MergedEntry nodes representing an entry 86da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 87da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Remarks: 88da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin This collapses multiple entries with the same fully qualified name into 89da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin one entry (e.g. if there are multiple entries in different kinds). 90da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 91da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin if not isinstance(node, metadata_model.Section) and \ 92da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin not isinstance(node, metadata_model.InnerNamespace): 93da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin raise TypeError("expected node to be a Section or InnerNamespace") 94da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 95586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin d = OrderedDict() 96da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin # remove the 'kinds' from the path between sec and the closest entries 97da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin # then search the immediate children of the search path 98da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin search_path = isinstance(node, metadata_model.Section) and node.kinds \ 99da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin or [node] 100da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin for i in search_path: 101da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin for entry in i.entries: 102da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin d[entry.name] = entry 103da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 104da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin for k,v in d.iteritems(): 105da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin yield v.merge() 106da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 107da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef path_name(node): 108da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 109da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Calculate a period-separated string path from the root to this element, 110da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin by joining the names of each node and excluding the Metadata/Kind nodes 111da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin from the path. 112da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 113da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 114da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin node: a Node instance 115da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 116da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 117da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A string path 118da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 119da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 120da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin isa = lambda x,y: isinstance(x, y) 121da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin fltr = lambda x: not isa(x, metadata_model.Metadata) and \ 122da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin not isa(x, metadata_model.Kind) 123da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 124da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin path = node.find_parents(fltr) 125da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin path = list(path) 126da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin path.reverse() 127da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin path.append(node) 128da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 129da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return ".".join((i.name for i in path)) 130da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 131ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yehdef ndk(name): 132ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh """ 133ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh Return the NDK version of given name, which replace 134ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh the leading "android" to "acamera" 135ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh 136ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh Args: 137ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh name: name string of an entry 138ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh 139ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh Returns: 140ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh A NDK version name string of the input name 141ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh """ 142ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh name_list = name.split(".") 143ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh if name_list[0] == "android": 144ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh name_list[0] = "acamera" 145ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh return ".".join(name_list) 146ea7662f32e3b6e6e74f0fedbd558b35784e6e219Yin-Chia Yeh 147c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yehdef protobuf_type(entry): 148c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh """ 149c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh Return the protocol buffer message type for input metadata entry. 150c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh Only support types used by static metadata right now 151c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 152c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh Returns: 153c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh A string of protocol buffer type. Ex: "optional int32" or "repeated RangeInt" 154c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh """ 155c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh typeName = None 156c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh if entry.typedef is None: 157c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh typeName = entry.type 158c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh else: 159c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh typeName = entry.typedef.name 160c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 161c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh typename_to_protobuftype = { 162c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "rational" : "Rational", 163c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "size" : "Size", 164c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "sizeF" : "SizeF", 165c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "rectangle" : "Rect", 166c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "streamConfigurationMap" : "StreamConfigurations", 167c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "rangeInt" : "RangeInt", 168c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "rangeLong" : "RangeLong", 169c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "colorSpaceTransform" : "ColorSpaceTransform", 170c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "blackLevelPattern" : "BlackLevelPattern", 171c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "byte" : "int32", # protocol buffer don't support byte 172c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "boolean" : "bool", 173c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "float" : "float", 174c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "double" : "double", 175c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "int32" : "int32", 176c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "int64" : "int64", 177c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh "enumList" : "int32" 178c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh } 179c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 180c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh if typeName not in typename_to_protobuftype: 181c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh print >> sys.stderr,\ 182c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh " ERROR: Could not find protocol buffer type for {%s} type {%s} typedef {%s}" % \ 183c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh (entry.name, entry.type, entry.typedef) 184c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 185c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh proto_type = typename_to_protobuftype[typeName] 186c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 187c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh prefix = "optional" 188c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh if entry.container == 'array': 189c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh has_variable_size = False 190c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh for size in entry.container_sizes: 191c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh try: 192c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh size_int = int(size) 193c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh except ValueError: 194c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh has_variable_size = True 195c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 196c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh if has_variable_size: 197c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh prefix = "repeated" 198c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 199c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh return "%s %s" %(prefix, proto_type) 200c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 201c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 202c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yehdef protobuf_name(entry): 203c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh """ 204c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh Return the protocol buffer field name for input metadata entry 205c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 206c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh Returns: 207c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh A string. Ex: "android_colorCorrection_availableAberrationModes" 208c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh """ 209c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh return entry.name.replace(".", "_") 210c9b27dd2a92203ee914485cbc52a4f583d763142Yin-Chia Yeh 211aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef has_descendants_with_enums(node): 212aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 213aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Determine whether or not the current node is or has any descendants with an 214aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Enum node. 215aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 216aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 217aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin node: a Node instance 218aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 219aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 220aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin True if it finds an Enum node in the subtree, False otherwise 221aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 222aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return bool(node.find_first(lambda x: isinstance(x, metadata_model.Enum))) 223aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 224aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef get_children_by_throwing_away_kind(node, member='entries'): 225aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 226aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Get the children of this node by compressing the subtree together by removing 227aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin the kind and then combining any children nodes with the same name together. 228aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 229aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 230aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin node: An instance of Section, InnerNamespace, or Kind 231aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 232aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 233aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin An iterable over the combined children of the subtree of node, 234aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin as if the Kinds never existed. 235aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 236aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Remarks: 237aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Not recursive. Call this function repeatedly on each child. 238aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 239aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 240aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if isinstance(node, metadata_model.Section): 241aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin # Note that this makes jump from Section to Kind, 242aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin # skipping the Kind entirely in the tree. 243aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin node_to_combine = node.combine_kinds_into_single_node() 244aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin else: 245aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin node_to_combine = node 246aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 247aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin combined_kind = node_to_combine.combine_children_by_name() 248aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 249aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return (i for i in getattr(combined_kind, member)) 250aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 251aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef get_children_by_filtering_kind(section, kind_name, member='entries'): 252aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 25323d4b2c087bd4286bf16bda83b6d9f72c5bb1718Eino-Ville Talvala Takes a section and yields the children of the merged kind under this section. 254aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 255aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 256aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin section: An instance of Section 257aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin kind_name: A name of the kind, i.e. 'dynamic' or 'static' or 'controls' 258aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 259aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 26023d4b2c087bd4286bf16bda83b6d9f72c5bb1718Eino-Ville Talvala An iterable over the children of the specified merged kind. 261aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 262aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 26323d4b2c087bd4286bf16bda83b6d9f72c5bb1718Eino-Ville Talvala matched_kind = next((i for i in section.merged_kinds if i.name == kind_name), None) 264aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 265aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if matched_kind: 266aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return getattr(matched_kind, member) 267aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin else: 268aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return () 269aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 270da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## 271da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## Filters 272da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin## 273da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 274da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# abcDef.xyz -> ABC_DEF_XYZ 275da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef csym(name): 276da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 277da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Convert an entry name string into an uppercase C symbol. 278da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 279da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 280da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A string 281da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 282da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Example: 283da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin csym('abcDef.xyz') == 'ABC_DEF_XYZ' 284da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 285da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin newstr = name 286da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin newstr = "".join([i.isupper() and ("_" + i) or i for i in newstr]).upper() 287da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin newstr = newstr.replace(".", "_") 288da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return newstr 289da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 290da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# abcDef.xyz -> abc_def_xyz 291da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef csyml(name): 292da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 293da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Convert an entry name string into a lowercase C symbol. 294da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 295da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 296da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A string 297da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 298da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Example: 299da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin csyml('abcDef.xyz') == 'abc_def_xyz' 300da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 301da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return csym(name).lower() 302da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 303da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# pad with spaces to make string len == size. add new line if too big 304da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef ljust(size, indent=4): 305da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 306da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Creates a function that given a string will pad it with spaces to make 307da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin the string length == size. Adds a new line if the string was too big. 308da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 309da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 310da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin size: an integer representing how much spacing should be added 311da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin indent: an integer representing the initial indendation level 312da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 313da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 314da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A function that takes a string and returns a string. 315da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 316da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Example: 317da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin ljust(8)("hello") == 'hello ' 318da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 319da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Remarks: 320da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Deprecated. Use pad instead since it works for non-first items in a 321da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Mako template. 322da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 323da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin def inner(what): 324da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin newstr = what.ljust(size) 325da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin if len(newstr) > size: 326da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return what + "\n" + "".ljust(indent + size) 327da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin else: 328da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return newstr 329da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return inner 330da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 331da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef _find_new_line(): 332da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 333da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin if _context_buf is None: 334da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin raise ValueError("Context buffer was not set") 335da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 336da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin buf = _context_buf 337da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin x = -1 # since the first read is always '' 338da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin cur_pos = buf.tell() 339da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin while buf.tell() > 0 and buf.read(1) != '\n': 340da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin buf.seek(cur_pos - x) 341da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin x = x + 1 342da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 343da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin buf.seek(cur_pos) 344da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 345da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return int(x) 346da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 347da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# Pad the string until the buffer reaches the desired column. 348da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# If string is too long, insert a new line with 'col' spaces instead 349da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef pad(col): 350da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 351da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Create a function that given a string will pad it to the specified column col. 352da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin If the string overflows the column, put the string on a new line and pad it. 353da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 354da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 355da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin col: an integer specifying the column number 356da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 357da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 358da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A function that given a string will produce a padded string. 359da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 360da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Example: 361da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin pad(8)("hello") == 'hello ' 362da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 363da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Remarks: 364da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin This keeps track of the line written by Mako so far, so it will always 365da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin align to the column number correctly. 366da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 367da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin def inner(what): 368da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin wut = int(col) 369da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin current_col = _find_new_line() 370da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 371da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin if len(what) > wut - current_col: 372da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return what + "\n".ljust(col) 373da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin else: 374da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return what.ljust(wut - current_col) 375da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return inner 376da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 377da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin# int32 -> TYPE_INT32, byte -> TYPE_BYTE, etc. note that enum -> TYPE_INT32 378da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkindef ctype_enum(what): 379da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 380da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Generate a camera_metadata_type_t symbol from a type string. 381da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 382da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Args: 383da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin what: a type string 384da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 385da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Returns: 386da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin A string representing the camera_metadata_type_t 387da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 388da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Example: 389da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin ctype_enum('int32') == 'TYPE_INT32' 390da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin ctype_enum('int64') == 'TYPE_INT64' 391da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin ctype_enum('float') == 'TYPE_FLOAT' 392da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin 393da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin Remarks: 394e6b664671e35984156e06e17531311a09864ac8bIgor Murashkin An enum is coerced to a byte since the rest of the camera_metadata 395da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin code doesn't support enums directly yet. 396da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin """ 397da1c314e080d33eb6b93a1d3da070c99b41e7b22Igor Murashkin return 'TYPE_%s' %(what.upper()) 398aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 399b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 400b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin# Calculate a java type name from an entry with a Typedef node 401b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkindef _jtypedef_type(entry): 402b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin typedef = entry.typedef 403b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin additional = '' 404b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 405b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # Hacky way to deal with arrays. Assume that if we have 406b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # size 'Constant x N' the Constant is part of the Typedef size. 407b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # So something sized just 'Constant', 'Constant1 x Constant2', etc 408b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # is not treated as a real java array. 409b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if entry.container == 'array': 410b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin has_variable_size = False 411b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin for size in entry.container_sizes: 412b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin try: 413b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin size_int = int(size) 414b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin except ValueError: 415b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin has_variable_size = True 416b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 417b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if has_variable_size: 418b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin additional = '[]' 419b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 420b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin try: 421b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin name = typedef.languages['java'] 422b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 423b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return "%s%s" %(name, additional) 424b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin except KeyError: 425b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return None 426b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 427b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin# Box if primitive. Otherwise leave unboxed. 428b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkindef _jtype_box(type_name): 429b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin mapping = { 430b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'boolean': 'Boolean', 431b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'byte': 'Byte', 432b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'int': 'Integer', 433b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'float': 'Float', 434b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'double': 'Double', 435b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'long': 'Long' 436b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin } 437b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 438b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return mapping.get(type_name, type_name) 439b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 440b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkindef jtype_unboxed(entry): 441aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 442b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin Calculate the Java type from an entry type string, to be used whenever we 443b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin need the regular type in Java. It's not boxed, so it can't be used as a 444b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin generic type argument when the entry type happens to resolve to a primitive. 445aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 446aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Remarks: 447aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Since Java generics cannot be instantiated with primitives, this version 448b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin is not applicable in that case. Use jtype_boxed instead for that. 449aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 450aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 451aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin The string representing the Java type. 452aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 453aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if not isinstance(entry, metadata_model.Entry): 454aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin raise ValueError("Expected entry to be an instance of Entry") 455aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 456b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin metadata_type = entry.type 457aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 458b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin java_type = None 459aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 460b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if entry.typedef: 461b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin typedef_name = _jtypedef_type(entry) 462b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if typedef_name: 463b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin java_type = typedef_name # already takes into account arrays 464aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 465b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if not java_type: 466e04dbd44c7d2043c31107ff3f9efdad71f438071Zhijun He if not java_type and entry.enum and metadata_type == 'byte': 467e04dbd44c7d2043c31107ff3f9efdad71f438071Zhijun He # Always map byte enums to Java ints, unless there's a typedef override 468d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala base_type = 'int' 469aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 470b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin else: 471b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin mapping = { 472b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'int32': 'int', 473b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'int64': 'long', 474b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'float': 'float', 475b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'double': 'double', 476b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'byte': 'byte', 477b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 'rational': 'Rational' 478b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin } 479b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 480b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin base_type = mapping[metadata_type] 481b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 482b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # Convert to array (enums, basic types) 483b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin if entry.container == 'array': 484b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin additional = '[]' 485b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin else: 486b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin additional = '' 487b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 488b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin java_type = '%s%s' %(base_type, additional) 489b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 490b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin # Now box this sucker. 491b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return java_type 492b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 493b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkindef jtype_boxed(entry): 494b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin """ 495b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin Calculate the Java type from an entry type string, to be used as a generic 496b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin type argument in Java. The type is guaranteed to inherit from Object. 497b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 498b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin It will only box when absolutely necessary, i.e. int -> Integer[], but 499b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin int[] -> int[]. 500aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 501b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin Remarks: 502b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin Since Java generics cannot be instantiated with primitives, this version 503b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin will use boxed types when absolutely required. 504aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 505b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin Returns: 506b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin The string representing the boxed Java type. 507b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin """ 508b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin unboxed_type = jtype_unboxed(entry) 509b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return _jtype_box(unboxed_type) 510b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin 51135a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkindef _is_jtype_generic(entry): 51235a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin """ 51335a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Determine whether or not the Java type represented by the entry type 51435a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin string and/or typedef is a Java generic. 51535a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 51635a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin For example, "Range<Integer>" would be considered a generic, whereas 51735a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin a "MeteringRectangle" or a plain "Integer" would not be considered a generic. 51835a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 51935a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Args: 52035a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin entry: An instance of an Entry node 52135a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 52235a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Returns: 52335a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin True if it's a java generic, False otherwise. 52435a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin """ 52535a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin if entry.typedef: 52635a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin local_typedef = _jtypedef_type(entry) 52735a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin if local_typedef: 52835a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin match = re.search(r'<.*>', local_typedef) 52935a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin return bool(match) 53035a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin return False 53135a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 532b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkindef _jtype_primitive(what): 533aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 534aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Calculate the Java type from an entry type string. 535aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 536aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Remarks: 537aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Makes a special exception for Rational, since it's a primitive in terms of 538aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin the C-library camera_metadata type system. 539aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 540aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 541aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin The string representing the primitive type 542aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 543aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin mapping = { 544aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'int32': 'int', 545aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'int64': 'long', 546aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'float': 'float', 547aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'double': 'double', 548aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'byte': 'byte', 549aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 'rational': 'Rational' 550aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin } 551aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 552aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin try: 553aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return mapping[what] 554aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin except KeyError as e: 555aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin raise ValueError("Can't map '%s' to a primitive, not supported" %what) 556aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 557aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef jclass(entry): 558aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 559aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Calculate the java Class reference string for an entry. 560aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 561aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 562aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin entry: an Entry node 563aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 564aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Example: 565aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <entry name="some_int" type="int32"/> 566aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <entry name="some_int_array" type="int32" container='array'/> 567aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 568aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin jclass(some_int) == 'int.class' 569aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin jclass(some_int_array) == 'int[].class' 570aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 571aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 572aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin The ClassName.class string 573aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 574aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 575b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin return "%s.class" %jtype_unboxed(entry) 576aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 57735a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkindef jkey_type_token(entry): 57835a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin """ 57935a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Calculate the java type token compatible with a Key constructor. 58035a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin This will be the Java Class<T> for non-generic classes, and a 58135a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin TypeReference<T> for generic classes. 58235a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 58335a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Args: 58435a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin entry: An entry node 58535a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 58635a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin Returns: 58735a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin The ClassName.class string, or 'new TypeReference<ClassName>() {{ }}' string 58835a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin """ 58935a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin if _is_jtype_generic(entry): 59035a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin return "new TypeReference<%s>() {{ }}" %(jtype_boxed(entry)) 59135a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin else: 59235a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin return jclass(entry) 59335a108fbfe7d174682187fa6a87f0590837924d0Igor Murashkin 594aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef jidentifier(what): 595aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 596aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Convert the input string into a valid Java identifier. 597aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 598aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 599aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin what: any identifier string 600aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 601aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 602aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin String with added underscores if necessary. 603aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 604aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if re.match("\d", what): 605aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return "_%s" %what 606aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin else: 607aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return what 608aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 609aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef enum_calculate_value_string(enum_value): 610aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 611aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Calculate the value of the enum, even if it does not have one explicitly 612aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin defined. 613aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 614aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin This looks back for the first enum value that has a predefined value and then 615aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin applies addition until we get the right value, using C-enum semantics. 616aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 617aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 618aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin enum_value: an EnumValue node with a valid Enum parent 619aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 620aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Example: 621aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <enum> 622aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <value>X</value> 623aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <value id="5">Y</value> 624aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin <value>Z</value> 625aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin </enum> 626aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 627aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin enum_calculate_value_string(X) == '0' 628aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin enum_calculate_Value_string(Y) == '5' 629aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin enum_calculate_value_string(Z) == '6' 630aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 631aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 632aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin String that represents the enum value as an integer literal. 633aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 634aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 635aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin enum_value_siblings = list(enum_value.parent.values) 636aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin this_index = enum_value_siblings.index(enum_value) 637aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 638aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin def is_hex_string(instr): 639aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return bool(re.match('0x[a-f0-9]+$', instr, re.IGNORECASE)) 640aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 641aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin base_value = 0 642aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin base_offset = 0 643aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin emit_as_hex = False 644aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 645aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin this_id = enum_value_siblings[this_index].id 646aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin while this_index != 0 and not this_id: 647aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin this_index -= 1 648aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin base_offset += 1 649aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin this_id = enum_value_siblings[this_index].id 650aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 651aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if this_id: 652aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin base_value = int(this_id, 0) # guess base 653aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin emit_as_hex = is_hex_string(this_id) 654aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 655aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin if emit_as_hex: 656aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return "0x%X" %(base_value + base_offset) 657aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin else: 658aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin return "%d" %(base_value + base_offset) 659aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 660aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef enumerate_with_last(iterable): 661aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 662aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Enumerate a sequence of iterable, while knowing if this element is the last in 663aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin the sequence or not. 664aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 665aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 666aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin iterable: an Iterable of some sequence 667aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 668aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Yields: 669aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin (element, bool) where the bool is True iff the element is last in the seq. 670aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 671aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin it = (i for i in iterable) 672aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 673aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin first = next(it) # OK: raises exception if it is empty 674aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 675aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin second = first # for when we have only 1 element in iterable 676aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 677aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin try: 678aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin while True: 679aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin second = next(it) 680aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin # more elements remaining. 681aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin yield (first, False) 682aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin first = second 683aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin except StopIteration: 684aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin # last element. no more elements left 685aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin yield (second, True) 686aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 687aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkindef pascal_case(what): 688aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 689aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Convert the first letter of a string to uppercase, to make the identifier 690aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin conform to PascalCase. 691aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 6925250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight If there are dots, remove the dots, and capitalize the letter following 6935250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight where the dot was. Letters that weren't following dots are left unchanged, 6945250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight except for the first letter of the string (which is made upper-case). 6955250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight 696aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 697aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin what: a string representing some identifier 698aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 699aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 700aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin String with first letter capitalized 701aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 702aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Example: 703aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin pascal_case("helloWorld") == "HelloWorld" 704aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin pascal_case("foo") == "Foo" 7055250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight pascal_case("hello.world") = "HelloWorld" 7065250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight pascal_case("fooBar.fooBar") = "FooBarFooBar" 7075250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight """ 7085250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight return "".join([s[0:1].upper() + s[1:] for s in what.split('.')]) 7095250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight 7105250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knightdef jkey_identifier(what): 7115250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight """ 7125250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight Return a Java identifier from a property name. 7135250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight 7145250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight Args: 7155250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight what: a string representing a property name. 7165250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight 7175250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight Returns: 7185250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight Java identifier corresponding to the property name. May need to be 7195250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight prepended with the appropriate Java class name by the caller of this 7205250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight function. Note that the outer namespace is stripped from the property 7215250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight name. 7225250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight 7235250aa1d42dea0773ab98fc0b2cd3f172067c050Timothy Knight Example: 724d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala jkey_identifier("android.lens.facing") == "LENS_FACING" 725aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 726d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala return csym(what[what.find('.') + 1:]) 727aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 728d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvaladef jenum_value(enum_entry, enum_value): 729aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 730d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala Calculate the Java name for an integer enum value 731aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 732aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Args: 733d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala enum: An enum-typed Entry node 734d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala value: An EnumValue node for the enum 735aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 736aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin Returns: 737aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin String representing the Java symbol 738aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin """ 739aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 740d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala cname = csym(enum_entry.name) 741d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala return cname[cname.find('_') + 1:] + '_' + enum_value.name 742d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 743567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvaladef generate_extra_javadoc_detail(entry): 744567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala """ 745567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala Returns a function to add extra details for an entry into a string for inclusion into 746567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala javadoc. Adds information about units, the list of enum values for this key, and the valid 747567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala range. 748567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala """ 749567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala def inner(text): 750567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.units: 751567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '\n\n<b>Units</b>: %s\n' % (dedent(entry.units)) 752567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')): 753567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '\n\n<b>Possible values:</b>\n<ul>\n' 754567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala for value in entry.enum.values: 755567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if not value.hidden: 756567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += ' <li>{@link #%s %s}</li>\n' % ( jenum_value(entry, value ), value.name ) 757567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '</ul>\n' 758567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.range: 759567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')): 760567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '\n\n<b>Available values for this device:</b><br>\n' 761567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala else: 762567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '\n\n<b>Range of valid values:</b><br>\n' 763567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '%s\n' % (dedent(entry.range)) 764567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.hwlevel != 'legacy': # covers any of (None, 'limited', 'full') 765567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += '\n\n<b>Optional</b> - This value may be {@code null} on some devices.\n' 766567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.hwlevel == 'full': 767567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += \ 768567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala '\n<b>Full capability</b> - \n' + \ 769567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 'Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the\n' + \ 770567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 'android.info.supportedHardwareLevel key\n' 771567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.hwlevel == 'limited': 772567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += \ 773567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala '\n<b>Limited capability</b> - \n' + \ 774567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 'Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the\n' + \ 775567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 'android.info.supportedHardwareLevel key\n' 776567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala if entry.hwlevel == 'legacy': 777567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala text += "\nThis key is available on all devices." 778567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 779567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala return text 780567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala return inner 781567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 782567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala 78363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvaladef javadoc(metadata, indent = 4): 784d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala """ 78563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala Returns a function to format a markdown syntax text block as a 78663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala javadoc comment section, given a set of metadata 787d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 788d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala Args: 78963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala metadata: A Metadata instance, representing the the top-level root 79063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala of the metadata for cross-referencing 791d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala indent: baseline level of indentation for javadoc block 792d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala Returns: 79363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala A function that transforms a String text block as follows: 794d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala - Indent and * for insertion into a Javadoc comment block 7958aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin - Trailing whitespace removed 7968aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin - Entire body rendered via markdown to generate HTML 79763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala - All tag names converted to appropriate Javadoc {@link} with @see 79863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala for each tag 799d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 800d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala Example: 801d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala "This is a comment for Javadoc\n" + 802d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala " with multiple lines, that should be \n" + 803d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala " formatted better\n" + 804d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala "\n" + 805d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala " That covers multiple lines as well\n" 80663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala " And references android.control.mode\n" 807d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 808d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala transforms to 8098aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin " * <p>This is a comment for Javadoc\n" + 810d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala " * with multiple lines, that should be\n" + 8118aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin " * formatted better</p>\n" + 8128aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin " * <p>That covers multiple lines as well</p>\n" + 81363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala " * and references {@link CaptureRequest#CONTROL_MODE android.control.mode}\n" + 81463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala " *\n" + 81563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala " * @see CaptureRequest#CONTROL_MODE\n" 816d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala """ 81763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala def javadoc_formatter(text): 81863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala comment_prefix = " " * indent + " * "; 819d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 82063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # render with markdown => HTML 82163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala javatext = md(text, JAVADOC_IMAGE_SRC_METADATA) 822d4e240adc06f10372f6e18b8ed23e14c4a4138d9Eino-Ville Talvala 823ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala # Identity transform for javadoc links 824ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala def javadoc_link_filter(target, shortname): 825ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala return '{@link %s %s}' % (target, shortname) 826ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 827ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala javatext = filter_links(javatext, javadoc_link_filter) 828ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 82963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Crossref tag names 83063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala kind_mapping = { 83163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 'static': 'CameraCharacteristics', 83263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 'dynamic': 'CaptureResult', 83363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 'controls': 'CaptureRequest' } 834aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 83563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Convert metadata entry "android.x.y.z" to form 83663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # "{@link CaptureRequest#X_Y_Z android.x.y.z}" 83763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala def javadoc_crossref_filter(node): 838c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh if node.applied_visibility in ('public', 'java_public'): 83963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return '{@link %s#%s %s}' % (kind_mapping[node.kind], 84063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala jkey_identifier(node.name), 84163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala node.name) 84263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala else: 84363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return node.name 844aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 84563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # For each public tag "android.x.y.z" referenced, add a 84663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # "@see CaptureRequest#X_Y_Z" 847ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala def javadoc_crossref_see_filter(node_set): 848c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh node_set = (x for x in node_set if x.applied_visibility in ('public', 'java_public')) 84963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 85063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala text = '\n' 85163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala for node in node_set: 85263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala text = text + '\n@see %s#%s' % (kind_mapping[node.kind], 85363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala jkey_identifier(node.name)) 85463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 85563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return text if text != '\n' else '' 85663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 857ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala javatext = filter_tags(javatext, metadata, javadoc_crossref_filter, javadoc_crossref_see_filter) 85863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 85963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala def line_filter(line): 86063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Indent each line 86163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Add ' * ' to it for stylistic reasons 86263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Strip right side of trailing whitespace 863567167ac6be36e732e98089d6e5d7d4f041f3323Eino-Ville Talvala return (comment_prefix + line).rstrip() 86463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 86563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Process each line with above filter 86663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala javatext = "\n".join(line_filter(i) for i in javatext.split("\n")) + "\n" 86763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 86863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return javatext 86963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 87063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return javadoc_formatter 871aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin 872d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yehdef ndkdoc(metadata, indent = 4): 873d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh """ 874d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Returns a function to format a markdown syntax text block as a 875d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh NDK camera API C/C++ comment section, given a set of metadata 876d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 877d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Args: 878d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh metadata: A Metadata instance, representing the the top-level root 879d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh of the metadata for cross-referencing 880d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh indent: baseline level of indentation for comment block 881d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Returns: 882d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh A function that transforms a String text block as follows: 883d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh - Indent and * for insertion into a comment block 884d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh - Trailing whitespace removed 885d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh - Entire body rendered via markdown 886d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh - All tag names converted to appropriate NDK tag name for each tag 887d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 888d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Example: 889d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh "This is a comment for NDK\n" + 890d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " with multiple lines, that should be \n" + 891d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " formatted better\n" + 892d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh "\n" + 893d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " That covers multiple lines as well\n" 894d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " And references android.control.mode\n" 895d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 896d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh transforms to 897d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * This is a comment for NDK\n" + 898d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * with multiple lines, that should be\n" + 899d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * formatted better\n" + 900d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * That covers multiple lines as well\n" + 901d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * and references ACAMERA_CONTROL_MODE\n" + 902d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " *\n" + 903d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh " * @see ACAMERA_CONTROL_MODE\n" 904d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh """ 905d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def ndkdoc_formatter(text): 906d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # render with markdown => HTML 907c9c2c6849c68ddb458d63b5f864ea76a8448a3d2Yin-Chia Yeh ndktext = md(text, NDKDOC_IMAGE_SRC_METADATA, False) 908d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 909d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # Convert metadata entry "android.x.y.z" to form 910d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # NDK tag format of "ACAMERA_X_Y_Z" 911d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def ndkdoc_crossref_filter(node): 912d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh if node.applied_ndk_visible == 'true': 913d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return csym(ndk(node.name)) 914d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh else: 915d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return node.name 916d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 917d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # For each public tag "android.x.y.z" referenced, add a 918d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # "@see ACAMERA_X_Y_Z" 919d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def ndkdoc_crossref_see_filter(node_set): 920d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh node_set = (x for x in node_set if x.applied_ndk_visible == 'true') 921d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 922d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh text = '\n' 923d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh for node in node_set: 924d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh text = text + '\n@see %s' % (csym(ndk(node.name))) 925d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 926d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return text if text != '\n' else '' 927d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 928d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh ndktext = filter_tags(ndktext, metadata, ndkdoc_crossref_filter, ndkdoc_crossref_see_filter) 929d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 930d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh ndktext = ndk_replace_tag_wildcards(ndktext, metadata) 931d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 932d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh comment_prefix = " " * indent + " * "; 933d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 934d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def line_filter(line): 935d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # Indent each line 936d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # Add ' * ' to it for stylistic reasons 937d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # Strip right side of trailing whitespace 938d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return (comment_prefix + line).rstrip() 939d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 940d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh # Process each line with above filter 941d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh ndktext = "\n".join(line_filter(i) for i in ndktext.split("\n")) + "\n" 942d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 943d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return ndktext 944d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 945d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return ndkdoc_formatter 946d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 94788b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkindef dedent(text): 94888b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin """ 94988b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin Remove all common indentation from every line but the 0th. 95088b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin This will avoid getting <code> blocks when rendering text via markdown. 95188b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin Ignoring the 0th line will also allow the 0th line not to be aligned. 95288b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin 95388b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin Args: 95488b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text: A string of text to dedent. 95588b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin 95688b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin Returns: 95788b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin String dedented by above rules. 95888b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin 95988b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin For example: 96088b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin assertEquals("bar\nline1\nline2", dedent("bar\n line1\n line2")) 96188b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin assertEquals("bar\nline1\nline2", dedent(" bar\n line1\n line2")) 96288b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin assertEquals("bar\n line1\nline2", dedent(" bar\n line1\n line2")) 96388b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin """ 96488b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text = textwrap.dedent(text) 96588b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text_lines = text.split('\n') 96688b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text_not_first = "\n".join(text_lines[1:]) 96788b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text_not_first = textwrap.dedent(text_not_first) 96888b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text = text_lines[0] + "\n" + text_not_first 96988b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin 97088b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin return text 97188b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin 972c9c2c6849c68ddb458d63b5f864ea76a8448a3d2Yin-Chia Yehdef md(text, img_src_prefix="", table_ext=True): 9738aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin """ 9748aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin Run text through markdown to produce HTML. 9758aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 9768aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin This also removes all common indentation from every line but the 0th. 9778aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin This will avoid getting <code> blocks in markdown. 9788aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin Ignoring the 0th line will also allow the 0th line not to be aligned. 9798aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 9801dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin Args: 9811dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin text: A markdown-syntax using block of text to format. 9821dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin img_src_prefix: An optional string to prepend to each <img src="target"/> 9831dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 9841dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin Returns: 9851dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin String rendered by markdown and other rules applied (see above). 9861dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 9878aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin For example, this avoids the following situation: 9888aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 9898aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <!-- Input --> 9908aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 9918aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <!--- can't use dedent directly since 'foo' has no indent --> 9928aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <notes>foo 9938aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar 9948aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar 9958aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin </notes> 9968aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 9978aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <!-- Bad Output -- > 9988aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <!-- if no dedent is done generated code looks like --> 9998aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <p>foo 10008aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <code><pre> 10018aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar 10028aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar</pre></code> 10038aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin </p> 10048aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 10058aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin Instead we get the more natural expected result: 10068aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 10078aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <!-- Good Output --> 10088aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin <p>foo 10098aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar 10108aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin bar</p> 10118aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 10128aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin """ 101388b858d5e4db3eb66fe570647626a592ebb6af91Igor Murashkin text = dedent(text) 10141dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 1015a48441daa766098190b40d5187ce1963d8a980afIgor Murashkin # full list of extensions at http://pythonhosted.org/Markdown/extensions/ 1016c9c2c6849c68ddb458d63b5f864ea76a8448a3d2Yin-Chia Yeh md_extensions = ['tables'] if table_ext else []# make <table> with ASCII |_| tables 10178aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin # render with markdown 1018a48441daa766098190b40d5187ce1963d8a980afIgor Murashkin text = markdown.markdown(text, md_extensions) 10191dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin 10201dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin # prepend a prefix to each <img src="foo"> -> <img src="${prefix}foo"> 10211dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin text = re.sub(r'src="([^"]*)"', 'src="' + img_src_prefix + r'\1"', text) 10221dd4ecb0ea0589610b3616459b707c2898889153Igor Murashkin return text 10238aa2a11bbff97d9789bb06cdc2e28dadb6c5926aIgor Murashkin 102463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvaladef filter_tags(text, metadata, filter_function, summary_function = None): 102563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala """ 102663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala Find all references to tags in the form outer_namespace.xxx.yyy[.zzz] in 102763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala the provided text, and pass them through filter_function and summary_function. 102863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 102963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala Used to linkify entry names in HMTL, javadoc output. 103063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 103163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala Args: 103263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala text: A string representing a block of text destined for output 103363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala metadata: A Metadata instance, the root of the metadata properties tree 103463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala filter_function: A Node->string function to apply to each node 103563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala when found in text; the string returned replaces the tag name in text. 103650f45c4d120ea1ad00017e5b850ed5bcf3261efeEino-Ville Talvala summary_function: A Node list->string function that is provided the list of 103750f45c4d120ea1ad00017e5b850ed5bcf3261efeEino-Ville Talvala unique tag nodes found in text, and which must return a string that is 103850f45c4d120ea1ad00017e5b850ed5bcf3261efeEino-Ville Talvala then appended to the end of the text. The list is sorted alphabetically 103950f45c4d120ea1ad00017e5b850ed5bcf3261efeEino-Ville Talvala by node name. 104063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala """ 104163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 104263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala tag_set = set() 104363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala def name_match(name): 104463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return lambda node: node.name == name 104563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 104663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # Match outer_namespace.x.y or outer_namespace.x.y.z, making sure 104763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # to grab .z and not just outer_namespace.x.y. (sloppy, but since we 1048ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala # check for validity, a few false positives don't hurt). 1049ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala # Try to ignore items of the form {@link <outer_namespace>... 105063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala for outer_namespace in metadata.outer_namespaces: 105163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 1052ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala tag_match = r"(?<!\{@link\s)" + outer_namespace.name + \ 10537fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala r"\.([a-zA-Z0-9\n]+)\.([a-zA-Z0-9\n]+)(\.[a-zA-Z0-9\n]+)?([/]?)" 105463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 105563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala def filter_sub(match): 105663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala whole_match = match.group(0) 105763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala section1 = match.group(1) 105863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala section2 = match.group(2) 105963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala section3 = match.group(3) 10607fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala end_slash = match.group(4) 10617fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala 10627fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Don't linkify things ending in slash (urls, for example) 10637fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if end_slash: 10647fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala return whole_match 10657fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala 10667fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate = "" 106763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 106863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala # First try a two-level match 10697fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate2 = "%s.%s.%s" % (outer_namespace.name, section1, section2) 107063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala got_two_level = False 107163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 10727fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala node = metadata.find_first(name_match(candidate2.replace('\n',''))) 10737fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if not node and '\n' in section2: 10747fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Linefeeds are ambiguous - was the intent to add a space, 10757fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # or continue a lengthy name? Try the former now. 10767fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate2b = "%s.%s.%s" % (outer_namespace.name, section1, section2[:section2.find('\n')]) 10777fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala node = metadata.find_first(name_match(candidate2b)) 10787fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if node: 10797fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate2 = candidate2b 108063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 108163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala if node: 10827fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Have two-level match 108363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala got_two_level = True 10847fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate = candidate2 10857fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala elif section3: 10867fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Try three-level match 10877fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate3 = "%s%s" % (candidate2, section3) 10887fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala node = metadata.find_first(name_match(candidate3.replace('\n',''))) 10897fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala 10907fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if not node and '\n' in section3: 10917fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Linefeeds are ambiguous - was the intent to add a space, 10927fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # or continue a lengthy name? Try the former now. 10937fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate3b = "%s%s" % (candidate2, section3[:section3.find('\n')]) 10947fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala node = metadata.find_first(name_match(candidate3b)) 10957fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if node: 10967fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate3 = candidate3b 10977fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala 10987fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala if node: 10997fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Have 3-level match 11007fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala candidate = candidate3 11017fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala 11027fabc1e635ee4213c8414c24f621e55a6aece1f1Eino-Ville Talvala # Replace match with crossref or complain if a likely match couldn't be matched 110363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 110463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala if node: 110563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala tag_set.add(node) 110663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return whole_match.replace(candidate,filter_function(node)) 110763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala else: 110863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala print >> sys.stderr,\ 110963c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala " WARNING: Could not crossref likely reference {%s}" % (match.group(0)) 111063c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return whole_match 111163c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 111263c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala text = re.sub(tag_match, filter_sub, text) 111363c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 111463c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala if summary_function is not None: 111550f45c4d120ea1ad00017e5b850ed5bcf3261efeEino-Ville Talvala return text + summary_function(sorted(tag_set, key=lambda x: x.name)) 111663c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala else: 111763c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala return text 111863c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala 1119d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yehdef ndk_replace_tag_wildcards(text, metadata): 1120d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh """ 1121d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Find all references to tags in the form android.xxx.* or android.xxx.yyy.* 1122d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh in the provided text, and replace them by NDK format of "ACAMERA_XXX_*" or 1123d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh "ACAMERA_XXX_YYY_*" 1124d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 1125d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh Args: 1126d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh text: A string representing a block of text destined for output 1127d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh metadata: A Metadata instance, the root of the metadata properties tree 1128d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh """ 1129d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh tag_match = r"android\.([a-zA-Z0-9\n]+)\.\*" 1130d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh tag_match_2 = r"android\.([a-zA-Z0-9\n]+)\.([a-zA-Z0-9\n]+)\*" 1131d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 1132d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def filter_sub(match): 1133d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return "ACAMERA_" + match.group(1).upper() + "_*" 1134d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh def filter_sub_2(match): 1135d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return "ACAMERA_" + match.group(1).upper() + match.group(2).upper() + "_*" 1136d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 1137d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh text = re.sub(tag_match, filter_sub, text) 1138d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh text = re.sub(tag_match_2, filter_sub_2, text) 1139d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh return text 1140d4eae97e331b077b30ba07463b61bc766f924143Yin-Chia Yeh 1141ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvaladef filter_links(text, filter_function, summary_function = None): 1142ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala """ 1143ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala Find all references to tags in the form {@link xxx#yyy [zzz]} in the 1144ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala provided text, and pass them through filter_function and 1145ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala summary_function. 1146ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1147ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala Used to linkify documentation cross-references in HMTL, javadoc output. 1148ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1149ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala Args: 1150ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala text: A string representing a block of text destined for output 1151ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala metadata: A Metadata instance, the root of the metadata properties tree 1152ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala filter_function: A (string, string)->string function to apply to each 'xxx#yyy', 1153ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala zzz pair when found in text; the string returned replaces the tag name in text. 1154ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala summary_function: A string list->string function that is provided the list of 1155ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala unique targets found in text, and which must return a string that is 1156ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala then appended to the end of the text. The list is sorted alphabetically 1157ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala by node name. 1158ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1159ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala """ 1160ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1161ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala target_set = set() 1162ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala def name_match(name): 1163ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala return lambda node: node.name == name 1164ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1165ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala tag_match = r"\{@link\s+([^\s\}]+)([^\}]*)\}" 1166ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1167ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala def filter_sub(match): 1168ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala whole_match = match.group(0) 1169ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala target = match.group(1) 1170ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala shortname = match.group(2).strip() 1171ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1172ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala #print "Found link '%s' as '%s' -> '%s'" % (target, shortname, filter_function(target, shortname)) 1173ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1174ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala # Replace match with crossref 1175ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala target_set.add(target) 1176ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala return filter_function(target, shortname) 1177ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1178ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala text = re.sub(tag_match, filter_sub, text) 1179ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1180ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala if summary_function is not None: 1181ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala return text + summary_function(sorted(target_set)) 1182ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala else: 1183ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala return text 1184ddda2bb917a1eb725c85d8c2b61bff2abf568a95Eino-Ville Talvala 1185f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvaladef any_visible(section, kind_name, visibilities): 1186f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala """ 1187f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Determine if entries in this section have an applied visibility that's in 1188f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala the list of given visibilities. 1189f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1190f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Args: 1191f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala section: A section of metadata 1192f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala kind_name: A name of the kind, i.e. 'dynamic' or 'static' or 'controls' 1193f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala visibilities: An iterable of visibilities to match against 1194f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1195f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Returns: 1196f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala True if the section has any entries with any of the given visibilities. False otherwise. 1197f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala """ 1198f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1199f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala for inner_namespace in get_children_by_filtering_kind(section, kind_name, 1200f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 'namespaces'): 1201f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala if any(filter_visibility(inner_namespace.merged_entries, visibilities)): 1202f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala return True 1203f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1204f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala return any(filter_visibility(get_children_by_filtering_kind(section, kind_name, 1205f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 'merged_entries'), 1206f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala visibilities)) 1207f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1208f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1209f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvaladef filter_visibility(entries, visibilities): 1210f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala """ 1211f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Remove entries whose applied visibility is not in the supplied visibilities. 1212f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1213f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Args: 1214f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala entries: An iterable of Entry nodes 1215f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala visibilities: An iterable of visibilities to filter against 1216f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala 1217f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala Yields: 1218f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala An iterable of Entry nodes 1219f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala """ 1220f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala return (e for e in entries if e.applied_visibility in visibilities) 12210b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12226c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkindef remove_synthetic(entries): 12236c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin """ 12246c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin Filter the given entries by removing those that are synthetic. 12256c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin 12266c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin Args: 12276c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin entries: An iterable of Entry nodes 12286c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin 12296c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin Yields: 12306c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin An iterable of Entry nodes 12316c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin """ 12326c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin return (e for e in entries if not e.synthetic) 12336c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin 1234c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yehdef filter_ndk_visible(entries): 1235c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh """ 1236c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh Filter the given entries by removing those that are not NDK visible. 1237c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh 1238c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh Args: 1239c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh entries: An iterable of Entry nodes 1240c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh 1241c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh Yields: 1242c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh An iterable of Entry nodes 1243c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh """ 1244c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh return (e for e in entries if e.applied_ndk_visible == 'true') 1245c6c2416a812ddb8bcb32fdefce1eff3a7ded9b61Yin-Chia Yeh 12460b080452cca90f215d10d636abfb47701d7518daIgor Murashkindef wbr(text): 12470b080452cca90f215d10d636abfb47701d7518daIgor Murashkin """ 12480b080452cca90f215d10d636abfb47701d7518daIgor Murashkin Insert word break hints for the browser in the form of <wbr> HTML tags. 12490b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12500b080452cca90f215d10d636abfb47701d7518daIgor Murashkin Word breaks are inserted inside an HTML node only, so the nodes themselves 12510b080452cca90f215d10d636abfb47701d7518daIgor Murashkin will not be changed. Attributes are also left unchanged. 12520b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12530b080452cca90f215d10d636abfb47701d7518daIgor Murashkin The following rules apply to insert word breaks: 12540b080452cca90f215d10d636abfb47701d7518daIgor Murashkin - For characters in [ '.', '/', '_' ] 12550b080452cca90f215d10d636abfb47701d7518daIgor Murashkin - For uppercase letters inside a multi-word X.Y.Z (at least 3 parts) 12560b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12570b080452cca90f215d10d636abfb47701d7518daIgor Murashkin Args: 12580b080452cca90f215d10d636abfb47701d7518daIgor Murashkin text: A string of text containing HTML content. 12590b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12600b080452cca90f215d10d636abfb47701d7518daIgor Murashkin Returns: 12610b080452cca90f215d10d636abfb47701d7518daIgor Murashkin A string with <wbr> inserted by the above rules. 12620b080452cca90f215d10d636abfb47701d7518daIgor Murashkin """ 12630b080452cca90f215d10d636abfb47701d7518daIgor Murashkin SPLIT_CHARS_LIST = ['.', '_', '/'] 12640b080452cca90f215d10d636abfb47701d7518daIgor Murashkin SPLIT_CHARS = r'([.|/|_/,]+)' # split by these characters 12650b080452cca90f215d10d636abfb47701d7518daIgor Murashkin CAP_LETTER_MIN = 3 # at least 3 components split by above chars, i.e. x.y.z 12660b080452cca90f215d10d636abfb47701d7518daIgor Murashkin def wbr_filter(text): 12670b080452cca90f215d10d636abfb47701d7518daIgor Murashkin new_txt = text 12680b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12690b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # for johnyOrange.appleCider.redGuardian also insert wbr before the caps 12700b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # => johny<wbr>Orange.apple<wbr>Cider.red<wbr>Guardian 12710b080452cca90f215d10d636abfb47701d7518daIgor Murashkin for words in text.split(" "): 12720b080452cca90f215d10d636abfb47701d7518daIgor Murashkin for char in SPLIT_CHARS_LIST: 12730b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # match at least x.y.z, don't match x or x.y 12740b080452cca90f215d10d636abfb47701d7518daIgor Murashkin if len(words.split(char)) >= CAP_LETTER_MIN: 12750b080452cca90f215d10d636abfb47701d7518daIgor Murashkin new_word = re.sub(r"([a-z])([A-Z])", r"\1<wbr>\2", words) 12760b080452cca90f215d10d636abfb47701d7518daIgor Murashkin new_txt = new_txt.replace(words, new_word) 12770b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12780b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # e.g. X/Y/Z -> X/<wbr>Y/<wbr>/Z. also for X.Y.Z, X_Y_Z. 12790b080452cca90f215d10d636abfb47701d7518daIgor Murashkin new_txt = re.sub(SPLIT_CHARS, r"\1<wbr>", new_txt) 12800b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12810b080452cca90f215d10d636abfb47701d7518daIgor Murashkin return new_txt 12820b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12830b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # Do not mangle HTML when doing the replace by using BeatifulSoup 12840b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # - Use the 'html.parser' to avoid inserting <html><body> when decoding 12850b080452cca90f215d10d636abfb47701d7518daIgor Murashkin soup = bs4.BeautifulSoup(text, features='html.parser') 12860b080452cca90f215d10d636abfb47701d7518daIgor Murashkin wbr_tag = lambda: soup.new_tag('wbr') # must generate new tag every time 12870b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12880b080452cca90f215d10d636abfb47701d7518daIgor Murashkin for navigable_string in soup.findAll(text=True): 12890b080452cca90f215d10d636abfb47701d7518daIgor Murashkin parent = navigable_string.parent 12900b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12910b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # Insert each '$text<wbr>$foo' before the old '$text$foo' 12920b080452cca90f215d10d636abfb47701d7518daIgor Murashkin split_by_wbr_list = wbr_filter(navigable_string).split("<wbr>") 12930b080452cca90f215d10d636abfb47701d7518daIgor Murashkin for (split_string, last) in enumerate_with_last(split_by_wbr_list): 12940b080452cca90f215d10d636abfb47701d7518daIgor Murashkin navigable_string.insert_before(split_string) 12950b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 12960b080452cca90f215d10d636abfb47701d7518daIgor Murashkin if not last: 12970b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # Note that 'insert' will move existing tags to this spot 12980b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # so make a new tag instead 12990b080452cca90f215d10d636abfb47701d7518daIgor Murashkin navigable_string.insert_before(wbr_tag()) 13000b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 13010b080452cca90f215d10d636abfb47701d7518daIgor Murashkin # Remove the old unmodified text 13020b080452cca90f215d10d636abfb47701d7518daIgor Murashkin navigable_string.extract() 13030b080452cca90f215d10d636abfb47701d7518daIgor Murashkin 13040b080452cca90f215d10d636abfb47701d7518daIgor Murashkin return soup.decode() 1305