1# SPDX-FileCopyrightText: 2020 GNOME Foundation 2# SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later 3 4import argparse 5import sys 6 7from . import gir, log, utils 8 9 10HELP_MSG = "Generates an index of all the symbols" 11 12 13def add_args(parser): 14 parser.add_argument("--add-include-path", action="append", dest="include_paths", default=[], 15 help="include paths for other GIR files") 16 parser.add_argument("infile", metavar="GIRFILE", type=argparse.FileType('r', encoding='UTF-8'), 17 default=sys.stdin, help="the GIR file to parse") 18 19 20def _print_function(function): 21 return_val = f" -> {log.color(function.return_value.target.ctype, 40)}" 22 func_name = f"{log.color(function.name, 220)}" 23 24 params = [] 25 for param in function.parameters: 26 params += [f"{param.name}: {log.color(param.target.ctype, 40)}"] 27 28 params = ', '.join(params) 29 30 return f"{func_name}({params}){return_val}" 31 32 33def _print_method(method): 34 return_val = f" -> {log.color(method.return_value.target.ctype, 40)}" 35 method_name = f"{log.color(method.name, 220)}" 36 37 params = ['self'] 38 for param in method.parameters: 39 params += [f"{param.name}: {log.color(param.target.ctype, 40)}"] 40 41 params = ', '.join(params) 42 43 return f"{method_name}({params}){return_val}" 44 45 46def _print_property(prop): 47 flags = [] 48 if prop.readable: 49 flags += [log.color('readable', 196)] 50 if prop.writable: 51 flags += [log.color('writable', 196)] 52 if prop.construct: 53 flags += [log.color('construct', 196)] 54 if prop.construct_only: 55 flags += [log.color('construct-only', 196)] 56 57 flags = ', '.join(flags) 58 59 return f"{log.color(prop.name, 220)}: {flags} -> {log.color(prop.target.name, 40)}" 60 61 62def _print_signal(signal): 63 return_val = f" -> {log.color(signal.return_value.target.ctype, 40)}" 64 signal_name = f"{log.color(signal.name, 220)}" 65 66 params = ['self'] 67 for param in signal.parameters: 68 params += [f"{param.name}: {log.color(param.target.ctype, 40)}"] 69 70 params = ', '.join(params) 71 72 return f"{signal_name}({params}){return_val}" 73 74 75def _print_enum_member(member): 76 return f"{log.color(member.name.upper(), 220)} = {member.value} ({member.nick})" 77 78 79def _print_enum_members(enum, sections=[], is_last_enum=False, is_last_branch=False): 80 if is_last_branch: 81 root_branch = ' ' 82 else: 83 root_branch = '│' 84 85 if is_last_enum: 86 enum_branch = ' ' 87 else: 88 enum_branch = '│' 89 90 if not sections: 91 sect_branch = '└──' 92 member_branch = ' ' 93 else: 94 sect_branch = '├──' 95 member_branch = '│' 96 97 title = str(log.color('Members', 36)) 98 log.log(f' {root_branch} {enum_branch} {sect_branch} {title}') 99 100 for i, member in enumerate(enum.members): 101 is_last_member = i == len(enum.members) - 1 102 enum_str = _print_enum_member(member) 103 104 if is_last_member: 105 leaf = '└──' 106 else: 107 leaf = '├──' 108 109 log.log(f' {root_branch} {enum_branch} {member_branch} {leaf} {enum_str}') 110 111 112def _print_enum_functions(enum, sections=[], is_last_enum=False, is_last_branch=False): 113 if not enum.functions: 114 return 115 116 if is_last_branch: 117 root_branch = ' ' 118 else: 119 root_branch = '│' 120 121 if is_last_enum: 122 enum_branch = ' ' 123 else: 124 enum_branch = '│' 125 126 if not sections: 127 sect_branch = '└──' 128 member_branch = ' ' 129 else: 130 sect_branch = '├──' 131 member_branch = '│' 132 133 title = str(log.color('Functions', 36)) 134 log.log(f' {root_branch} {enum_branch} {sect_branch} {title}') 135 136 for i, function in enumerate(enum.functions): 137 is_last_function = i == len(enum.functions) - 1 138 func_str = _print_function(function) 139 140 if is_last_function: 141 leaf = '└──' 142 else: 143 leaf = '├──' 144 145 log.log(f' {root_branch} {enum_branch} {member_branch} {leaf} {func_str}') 146 147 148def _print_class_implements(cls, sections=[], is_last_class=False): 149 if not cls.implements: 150 return 151 152 root_branch = '│' 153 154 if is_last_class: 155 ifaces_branch = ' ' 156 else: 157 ifaces_branch = '│' 158 159 if not sections: 160 sect_branch = '└──' 161 iface_branch = ' ' 162 else: 163 sect_branch = '├──' 164 iface_branch = '│' 165 166 title = str(log.color('Implements', 36)) 167 log.log(f' {root_branch} {ifaces_branch} {sect_branch} {title}') 168 169 for i, iface in enumerate(cls.implements): 170 is_last_iface = i == len(cls.implements) - 1 171 if is_last_iface: 172 leaf = '└──' 173 else: 174 leaf = '├──' 175 176 log.log(f' {root_branch} {ifaces_branch} {iface_branch} {leaf} {iface}') 177 178 179def _print_class_properties(cls, sections=[], is_last_class=False): 180 if not cls.properties: 181 return 182 183 root_branch = '│' 184 185 if is_last_class: 186 props_branch = ' ' 187 else: 188 props_branch = '│' 189 190 if not sections: 191 sect_branch = '└──' 192 prop_branch = ' ' 193 else: 194 sect_branch = '├──' 195 prop_branch = '│' 196 197 title = str(log.color('Properties', 36)) 198 log.log(f' {root_branch} {props_branch} {sect_branch} {title}') 199 200 for i, prop in enumerate(cls.properties.values()): 201 is_last_prop = i == len(cls.properties) - 1 202 prop_str = _print_property(prop) 203 if is_last_prop: 204 leaf = '└──' 205 else: 206 leaf = '├──' 207 208 log.log(f' {root_branch} {props_branch} {prop_branch} {leaf} {prop_str}') 209 210 211def _print_class_signals(cls, sections=[], is_last_class=False): 212 if not cls.signals: 213 return 214 215 root_branch = '│' 216 217 if is_last_class: 218 signals_branch = ' ' 219 else: 220 signals_branch = '│' 221 222 if not sections: 223 sect_branch = '└──' 224 signal_branch = ' ' 225 else: 226 sect_branch = '├──' 227 signal_branch = '│' 228 229 title = str(log.color('Signals', 36)) 230 log.log(f' {root_branch} {signals_branch} {sect_branch} {title}') 231 232 for i, signal in enumerate(cls.signals.values()): 233 is_last_signal = i == len(cls.signals) - 1 234 signal_str = _print_signal(signal) 235 if is_last_signal: 236 leaf = '└──' 237 else: 238 leaf = '├──' 239 240 log.log(f' {root_branch} {signals_branch} {signal_branch} {leaf} {signal_str}') 241 242 243def _print_class_constructors(cls, sections=[], is_last_class=False): 244 if not cls.constructors: 245 return 246 247 root_branch = '│' 248 249 if is_last_class: 250 ctors_branch = ' ' 251 else: 252 ctors_branch = '│' 253 254 if not sections: 255 sect_branch = '└──' 256 ctor_branch = ' ' 257 else: 258 sect_branch = '├──' 259 ctor_branch = '│' 260 261 title = str(log.color('Constructors', 36)) 262 log.log(f' {root_branch} {ctors_branch} {sect_branch} {title}') 263 264 for i, ctor in enumerate(cls.constructors): 265 is_last_ctor = i == len(cls.constructors) - 1 266 ctor_str = _print_function(ctor) 267 if is_last_ctor: 268 leaf = '└──' 269 else: 270 leaf = '├──' 271 272 log.log(f' {root_branch} {ctors_branch} {ctor_branch} {leaf} {ctor_str}') 273 274 275def _print_class_methods(cls, sections=[], is_last_class=False): 276 if not cls.methods: 277 return 278 279 root_branch = '│' 280 281 if is_last_class: 282 methods_branch = ' ' 283 else: 284 methods_branch = '│' 285 286 if not sections: 287 sect_branch = '└──' 288 method_branch = ' ' 289 else: 290 sect_branch = '├──' 291 method_branch = '│' 292 293 title = str(log.color('Methods', 36)) 294 log.log(f' {root_branch} {methods_branch} {sect_branch} {title}') 295 296 for i, method in enumerate(cls.methods): 297 is_last_method = i == len(cls.methods) - 1 298 method_str = _print_method(method) 299 if is_last_method: 300 leaf = '└──' 301 else: 302 leaf = '├──' 303 304 log.log(f' {root_branch} {methods_branch} {method_branch} {leaf} {method_str}') 305 306 307def _print_class_functions(cls, sections=[], is_last_class=False): 308 if not cls.functions: 309 return 310 311 root_branch = '│' 312 313 if is_last_class: 314 functions_branch = ' ' 315 else: 316 functions_branch = '│' 317 318 if not sections: 319 sect_branch = '└──' 320 function_branch = ' ' 321 else: 322 sect_branch = '├──' 323 function_branch = '│' 324 325 title = str(log.color('Functions', 36)) 326 log.log(f' {root_branch} {functions_branch} {sect_branch} {title}') 327 328 for i, function in enumerate(cls.functions): 329 is_last_func = i == len(cls.functions) - 1 330 func_str = _print_function(function) 331 if is_last_func: 332 leaf = '└──' 333 else: 334 leaf = '├──' 335 336 log.log(f' {root_branch} {functions_branch} {function_branch} {leaf} {func_str}') 337 338 339def gen_tree(repository): 340 includes = ', '.join([str(repository.includes[r]) for r in repository.includes]) 341 c_includes = ', '.join(repository.c_includes) 342 packages = ', '.join(repository.packages) 343 344 title = str(log.color('Repository', 12)) 345 log.log(f'{title}') 346 log.log(f'├── Includes: {includes}') 347 log.log(f'├── C headers: {c_includes}') 348 log.log(f'├── Packages: {packages}') 349 350 namespace = repository.namespace 351 shlibs = ', '.join(namespace.get_shared_libraries()) 352 353 aliases = sorted(namespace.get_aliases(), key=lambda alias: alias.name.lower()) 354 classes = sorted(namespace.get_classes(), key=lambda cls: cls.name.lower()) 355 constants = sorted(namespace.get_constants(), key=lambda const: const.name.lower()) 356 domains = sorted(namespace.get_error_domains(), key=lambda domain: domain.name.lower()) 357 enums = sorted(namespace.get_enumerations(), key=lambda enum: enum.name.lower()) 358 functions = sorted(namespace.get_functions(), key=lambda func: func.name.lower()) 359 interfaces = sorted(namespace.get_interfaces(), key=lambda interface: interface.name.lower()) 360 records = sorted(namespace.get_records(), key=lambda record: record.name.lower()) 361 unions = sorted(namespace.get_unions(), key=lambda union: union.name.lower()) 362 363 title = str(log.color('Namespace', 36)) 364 log.log(f'└── {title}: {namespace.name}, version: {namespace.version}') 365 log.log(f' ├── Shared libraries: {shlibs}') 366 367 title = str(log.color('Classes', 36)) 368 log.log(f' ├── {title}') 369 370 if len(classes) == 0: 371 log.log(' │ └── None') 372 else: 373 for i, cls in enumerate(classes): 374 is_last_class = i == len(classes) - 1 375 if is_last_class: 376 log.log(f' │ └── {cls.name} - parent: {cls.parent}, abstract: {log.color(cls.abstract, 196)}') 377 else: 378 log.log(f' │ ├── {cls.name} - parent: {cls.parent}, abstract: {log.color(cls.abstract, 196)}') 379 380 sections = [] 381 if cls.implements: 382 sections += ['implements'] 383 if cls.properties: 384 sections += ['properties'] 385 if cls.signals: 386 sections += ['signals'] 387 if cls.constructors: 388 sections += ['constructors'] 389 if cls.methods: 390 sections += ['methods'] 391 if cls.functions: 392 sections += ['functions'] 393 394 if 'implements' in sections: 395 sections.remove('implements') 396 _print_class_implements(cls, sections, is_last_class) 397 if 'properties' in sections: 398 sections.remove('properties') 399 _print_class_properties(cls, sections, is_last_class) 400 if 'signals' in sections: 401 sections.remove('signals') 402 _print_class_signals(cls, sections, is_last_class) 403 if 'constructors' in sections: 404 sections.remove('constructors') 405 _print_class_constructors(cls, sections, is_last_class) 406 if 'methods' in sections: 407 sections.remove('methods') 408 _print_class_methods(cls, sections, is_last_class) 409 if 'functions' in sections: 410 sections.remove('functions') 411 _print_class_functions(cls, sections, is_last_class) 412 413 title = str(log.color('Interfaces', 36)) 414 log.log(f' ├── {title}') 415 416 if len(interfaces) == 0: 417 log.log(' │ └── None') 418 else: 419 for i, iface in enumerate(interfaces): 420 is_last_iface = i == len(interfaces) - 1 421 if is_last_iface: 422 log.log(f' │ └── {iface.name}, prerequisite: {iface.prerequisite}') 423 else: 424 log.log(f' │ ├── {iface.name}, prerequisite: {iface.prerequisite}') 425 426 sections = [] 427 if iface.properties: 428 sections += ['properties'] 429 if iface.signals: 430 sections += ['signals'] 431 if iface.methods: 432 sections += ['methods'] 433 if iface.functions: 434 sections += ['functions'] 435 436 if 'properties' in sections: 437 sections.remove('properties') 438 _print_class_properties(iface, sections, is_last_iface) 439 if 'signals' in sections: 440 sections.remove('signals') 441 _print_class_signals(iface, sections, is_last_iface) 442 if 'methods' in sections: 443 sections.remove('methods') 444 _print_class_methods(iface, sections, is_last_iface) 445 if 'functions' in sections: 446 sections.remove('functions') 447 _print_class_functions(iface, sections, is_last_iface) 448 449 title = str(log.color('Records', 36)) 450 log.log(f' ├── {title}') 451 452 if len(records) == 0: 453 log.log(' │ └── None') 454 else: 455 for i, record in enumerate(records): 456 is_last_record = i == len(records) - 1 457 if is_last_record: 458 log.log(f' │ └── {record.name}') 459 else: 460 log.log(f' │ ├── {record.name}') 461 462 sections = [] 463 if record.constructors: 464 sections += ['constructors'] 465 if record.methods: 466 sections += ['methods'] 467 if record.functions: 468 sections += ['functions'] 469 470 if 'constructors' in sections: 471 sections.remove('constructors') 472 _print_class_constructors(record, sections, is_last_record) 473 if 'methods' in sections: 474 sections.remove('methods') 475 _print_class_methods(record, sections, is_last_record) 476 if 'functions' in sections: 477 sections.remove('functions') 478 _print_class_functions(record, sections, is_last_record) 479 480 title = str(log.color('Unions', 36)) 481 log.log(f' ├── {title}') 482 483 if len(records) == 0: 484 log.log(' │ └── None') 485 else: 486 for i, union in enumerate(unions): 487 is_last_union = i == len(unions) - 1 488 if is_last_union: 489 log.log(f' │ └── {union.name}') 490 else: 491 log.log(f' │ ├── {union.name}') 492 493 sections = [] 494 if union.constructors: 495 sections += ['constructors'] 496 if union.methods: 497 sections += ['methods'] 498 if union.functions: 499 sections += ['functions'] 500 501 if 'constructors' in sections: 502 sections.remove('constructors') 503 _print_class_constructors(union, sections, is_last_union) 504 if 'methods' in sections: 505 sections.remove('methods') 506 _print_class_methods(union, sections, is_last_union) 507 if 'functions' in sections: 508 sections.remove('functions') 509 _print_class_functions(union, sections, is_last_union) 510 511 title = str(log.color('Functions', 36)) 512 log.log(f' ├── {title}') 513 514 if len(aliases) == 0: 515 log.log(' │ └── None') 516 else: 517 for i, func in enumerate(functions): 518 is_last_func = i == len(functions) - 1 519 func_str = _print_function(func) 520 if is_last_func: 521 log.log(f' │ ├── {func_str}') 522 else: 523 log.log(f' │ └── {func_str}') 524 525 title = str(log.color('Aliases', 36)) 526 log.log(f' ├── {title}') 527 528 if len(aliases) == 0: 529 log.log(' │ └── None') 530 else: 531 for i in range(len(aliases)): 532 alias = aliases[i] 533 if i < len(aliases) - 1: 534 log.log(f' │ ├── {log.color(alias.name, 220)} → {alias.target.name} ({log.color(alias.target.ctype, 40)})') 535 else: 536 log.log(f' │ └── {log.color(alias.name, 220)} → {alias.target.name} ({log.color(alias.target.ctype, 40)})') 537 538 title = str(log.color('Constants', 36)) 539 log.log(f' ├── {title}') 540 541 if len(constants) == 0: 542 log.log(' │ └── None') 543 else: 544 for i in range(len(constants)): 545 const = constants[i] 546 if i < len(constants) - 1: 547 log.log(f' │ ├── {log.color(const.name, 220)} = {const.value} ({log.color(const.target.ctype, 40)})') 548 else: 549 log.log(f' │ └── {log.color(const.name, 220)} = {const.value} ({log.color(const.target.ctype, 40)})') 550 551 title = str(log.color('Enumerations', 36)) 552 log.log(f' ├── {title}') 553 554 if len(enums) == 0: 555 log.log(' │ └── None') 556 else: 557 for i, enum in enumerate(enums): 558 is_last_enum = i == len(enums) - 1 559 if is_last_enum: 560 log.log(f' │ └── {enum.name}') 561 else: 562 log.log(f' │ ├── {enum.name}') 563 564 sections = [] 565 if enum.members: 566 sections += ['members'] 567 if enum.functions: 568 sections += ['functions'] 569 570 if 'members' in sections: 571 sections.remove('members') 572 _print_enum_members(enum, sections, is_last_enum) 573 if 'functions' in sections: 574 sections.remove('functions') 575 _print_enum_functions(enum, sections, is_last_enum) 576 577 title = str(log.color('Error domains', 36)) 578 log.log(f' └── {title}') 579 580 if len(domains) == 0: 581 log.log(' └── None') 582 else: 583 for i, domain in enumerate(domains): 584 is_last_domain = i == len(domains) - 1 585 if is_last_domain: 586 log.log(f' └── {domain.name} - domain: {domain.domain}') 587 else: 588 log.log(f' ├── {domain.name} - domain: {domain.domain}') 589 590 sections = [] 591 if domain.members: 592 sections += ['members'] 593 if domain.functions: 594 sections += ['functions'] 595 596 if 'members' in sections: 597 sections.remove('members') 598 _print_enum_members(domain, sections, is_last_domain, True) 599 if 'functions' in sections: 600 sections.remove('functions') 601 _print_enum_functions(domain, sections, is_last_domain, True) 602 603 604def run(options): 605 paths = [] 606 paths.extend(options.include_paths) 607 paths.extend(utils.default_search_paths()) 608 log.info(f"Search paths: {paths}") 609 610 parser = gir.GirParser(search_paths=paths) 611 parser.parse(options.infile) 612 613 log.checkpoint() 614 gen_tree(parser.get_repository()) 615 616 return 0 617