2904215904f1e62317b16bb372a6b176c1f800bd braney Sat Jul 25 09:58:54 2026 -0700 add an inventory of track-scoped cart variables refs #37838 Before changing the cart format we need to know what is actually stored in it. cartTrackVarCatalog.py holds a curated catalog of the 340 track-scoped cart variables in the tree, arranged as the hierarchy a JSON cart would use: track name, then the variables common to any track, then a layer per track type, then the leaf groups shared across types. It emits either JSON or a browsable HTML page, and --check verifies that every leaf group a type refers to exists. harvestCartVars.py is the scanner that seeds it. It finds the two ways a track-scoped name gets built, cart*ClosestToHome() and safef("%s.%s"), resolves macro identifiers to their string values, and attributes each hit to the function that reads or writes it. Its output still needs curation by hand, since it cannot tell a cart variable from a table name or a filename suffix. No makefile: this is a documentation generator, so it is left out of the utils DIRS list, same as hg/utils/otto. diff --git src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py new file mode 100755 index 00000000000..a258c7a4fa0 --- /dev/null +++ src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py @@ -0,0 +1,1702 @@ +#!/usr/bin/env python3 +"""cartTrackVarCatalog.py - the registry of track-scoped cart variables. + +Refs #37838. This is the hand-curated catalog that backs two things: + + 1. The JSON cart schema (#37838) - the hierarchy below is the shape the + stored cart wants to grow into: track name at the top, then the vars + every track has, then a per-type section, then nested leaf groups. + 2. The planned cart accessor layer - each entry names one variable, its + value type, its separator, and where the tree reads it, so accessors + can be generated or at least checked against reality. + +Harvested mechanically from cart*ClosestToHome() and safef("%s.%s") call +sites in hg/lib, hg/hgTracks, hg/hgTrackUi and hg/cgilib, then curated by +hand: names that turned out to be table names, file suffixes or non-cart +strings were dropped, macro identifiers were resolved to their values, and +the type/enum/default columns were read out of the UI code. + +Usage: + cartTrackVarCatalog.py --json out.json + cartTrackVarCatalog.py --html out.html + cartTrackVarCatalog.py --check # sanity checks, prints counts +""" + +import argparse +import html +import json +import re +import sys + +# --------------------------------------------------------------------------- +# how a track-scoped name is built +# --------------------------------------------------------------------------- + +NAMING = { + "canonical": ".", + "legacy": "_", + "legacyNote": + "The underscore form predates the dot form. cartRemoveAllForTdb() " + "(hg/lib/cart.c:3306) removes both prefixes plus the bare track name, " + "and carries the comment 'All should be {track}.{varName}'. Any " + "rewrite should keep reading both.", + "lookupOrder": [ + ".", + "..", + ".", + ], + "lookupOrderSrc": "hg/lib/cart.c:cartLookUpVariableClosestToHome", + "lookupOrderNote": + "parentLevel=TRUE starts the search at the parent, so a subtrack " + "setting always wins over its view, which wins over its composite. " + "The JSON form needs to preserve that three-level fallback, not " + "flatten it.", + "trackNamePrefixes": [ + {"prefix": "hub__", "what": "track hub track", + "src": "hg/lib/trackHub.c"}, + {"prefix": "ct_", "what": "custom track", + "src": "hg/lib/customTrack.c"}, + {"prefix": "dup__", "what": "duplicated track", + "src": "hg/inc/dupTrack.h:DUP_TRACK_PREFIX"}, + ], + "valueEncoding": + "Everything is a string in the cart hash. The 'type' column below is " + "how the reader interprets it, and is what the JSON form could encode " + "natively. 'list' vars are multi-valued: the same name appears more " + "than once in the var=val encoding and must become a JSON array.", +} + +# --------------------------------------------------------------------------- +# helpers +# --------------------------------------------------------------------------- + +def v(name, type_, src, sep=".", values=None, default=None, note=None, + tdb=None, multi=False): + """One catalog entry. + + name variable name after the prefix and separator + type_ bool | int | float | string | enum | list | color | hidden + src file:line where the tree reads or writes it + sep '.' (canonical) or '_' (legacy) + values allowed values for enums + tdb trackDb setting that supplies the default, if differently named + """ + d = {"name": name, "type": type_, "sep": sep, "src": src} + if values: + d["values"] = values + if default is not None: + d["default"] = default + if tdb: + d["tdbDefault"] = tdb + if multi: + d["multi"] = True + if note: + d["note"] = note + return d + + +# --------------------------------------------------------------------------- +# LEVEL 2: variables every track can have, whatever its type +# --------------------------------------------------------------------------- + +COMMON = { + "visibility": { + "what": "What the track is set to. The only var that is the bare " + "track name with no suffix at all.", + "vars": [ + v("", "enum", "hg/lib/hui.c:9954", sep="", + values=["hide", "dense", "squish", "pack", "full"], + note="Bare . For a superTrack the values are " + "'show'/'hide' instead (hg/lib/hui.c:9887). This is the " + "var #37838 discussed moving under a 'vis.' prefix."), + v("_sel", "bool", "hg/lib/hui.c:5434", sep="_", + note="Subtrack/composite-member checkbox. Four-state in the " + "UI (checked, unchecked, checked-disabled) but stored 0/1; " + "see fourState* in hg/inc/hui.h."), + v("_hideKids", "bool", "hg/hgTracks/hgTracks.c:7652", sep="_", + note="Container collapsed in hgTracks, children not drawn."), + v("_faux", "hidden", "hg/lib/hui.c:5524", sep="_", + note="UI-only element id, not persisted state."), + v("_toggle", "hidden", "hg/lib/hui.c:5529", sep="_", + note="UI-only element id, not persisted state."), + ], + }, + "layout": { + "what": "Where the track sits in the image and how tall it is.", + "vars": [ + v("priority", "float", "hg/lib/hui.c:tdbAddPrioritiesFromCart", + tdb="priority", + note="User drag-reorder override of the trackDb priority."), + v("group", "string", "hg/hgTracks/hgTracks.c:groupTracks", + note="User moved the track into a different track group."), + v("_imgOrd", "int", "hg/hgTracks/imageV2.c:flatTracksSort", sep="_", + note="Row order in the image, set by drag-reorder in " + "hgTracks.js. Distinct from priority."), + v("heightPer", "int", "hg/inc/wiggle.h:HEIGHTPER", + default="128", tdb="maxHeightPixels", + note="Track height in pixels. Shared by wig, lolly, interact, " + "long, sample and vcf haplotype displays."), + ], + }, + "color": { + "what": "Per-track color override, offered for any track whose type " + "supports it (tdbSupportsColorOverride).", + "vars": [ + v("colorOverride", "color", "hg/lib/hui.c:colorTrackOption", + note="RGB as '#rrggbb'."), + v("colorOverrideOn", "bool", "hg/lib/hui.c:colorTrackOption"), + ], + }, + "ui": { + "what": "State of the hgTrackUi page itself, not of the drawing.", + "vars": [ + v("section_
_close", "bool", + "hg/lib/jsHelper.c:411", + note="One per collapsible section on the track's config page " + "(jsBeginCollapsibleSection). Known sections include " + "colorByAttribute, superDescription, superMembers."), + v("_button", "hidden", "hg/hgTracks/config.c:321", sep="_"), + v("_defaultBut", "hidden", "hg/hgTracks/config.c:348", sep="_"), + v("_hideAllBut", "hidden", "hg/hgTracks/config.c:331", sep="_"), + v("_showAllBut", "hidden", "hg/hgTracks/config.c:342", sep="_"), + v("_edit", "hidden", "hg/hgTracks/hgTracks.c:10121", sep="_"), + ], + }, + "dataFilters": { + "what": "Filters offered for many types, not tied to one of them.", + "vars": [ + v("nameFilter", "string", "hg/lib/hui.c:filterNameOption", + note="Wildcard match on item name."), + v("doMergeItems", "bool", "hg/inc/hui.h:MERGESPAN_CART_SETTING", + tdb="mergeSpannedItems", + note="Collapse items that span the whole window into one."), + v("doWiggle", "bool", "hg/lib/hui.c:wigOption", + note="Draw a bed/genePred/psl/bam type as a coverage wiggle. " + "When on, the whole wig type group below applies too."), + v("squishyPackPoint", "float", "hg/lib/hui.c:squishyPackOption", + note="Row count past which pack degrades to squish."), + v("doSnake", "bool", "hg/lib/hui.c:snakeOption", + note="Draw a chain/psl as a snake."), + ], + }, +} + +# --------------------------------------------------------------------------- +# LEVEL 2b: containers - composite, view, superTrack, multiWig, faceted +# --------------------------------------------------------------------------- + +CONTAINER = { + "composite": { + "what": "Vars a composite parent owns. Subtrack selection lives on " + "the child (_sel), not here.", + "vars": [ + v("displaySubtracks", "enum", "hg/lib/hui.c:compositeUiSubtracks", + values=["all", "selected"]), + v("hideEmptySubtracks", "bool", + "hg/lib/hui.c:compositeHideEmptySubtracks", + tdb="hideEmptySubtracks"), + v("sortOrder", "string", "hg/lib/hui.c:sortOrderGet", + note="Subtrack table sort, e.g. 'cellType=+ view=-'."), + v("filterComp.", "list", "hg/lib/hui.c:3119", multi=True, + note="One per ABC dimension of a filterComposite. 'All' means " + "every option selected."), + v("subGroup", "string", "hg/lib/hui.c:2905", + note="trackDb-side dimension definition, read back when " + "rebuilding the matrix."), + ], + }, + "view": { + "what": "A composite view is a middle namespace, not a var of its " + "own: any type-layer var can appear as " + "...", + "vars": [ + v(".", "varies", + "hg/lib/cart.c:cartLookUpVariableClosestToHome", + note="Middle level of the three-level lookup."), + v("_link", "hidden", "hg/lib/hui.c:hCompositeDisplayViewDropDowns", + sep="_"), + ], + }, + "superTrack": { + "what": "SuperTracks have no drawing settings of their own.", + "vars": [ + v("", "enum", "hg/lib/hui.c:9887", sep="", + values=["show", "hide"]), + v("_check", "hidden", "hg/hgTrackUi/hgTrackUi.c:2861", sep="_"), + v("_link", "hidden", "hg/hgTrackUi/hgTrackUi.c:2894", sep="_"), + ], + }, + "multiWig": { + "what": "Overlay container. Uses the wig type group plus these.", + "vars": [ + v("aggregate", "enum", "hg/inc/wiggle.h:AGGREGATE", + values=["none", "transparentOverlay", "solidOverlay", + "stacked", "add", "subtract"]), + v("viewFunc", "enum", "hg/inc/wiggle.h:VIEWFUNC", + values=["showAll", "addAll", "subtractAll"]), + v("showSubtrackColorOnUi", "bool", + "hg/inc/hui.h:SUBTRACK_COLOR_PATCH"), + ], + }, + "facetedComposite": { + "what": "compositeTrack faceted. Facet state is keyed off a var " + "prefix, not the track name; see the exceptions section.", + "vars": [ + v("_facet_selList", "string", "hg/lib/facetedTable.c:87", sep="_"), + v("_facet_fieldName", "string", "hg/lib/facetedTable.c:103", + sep="_"), + v("_facet_fieldVal", "string", "hg/lib/facetedTable.c:111", + sep="_"), + v("_facet_op", "string", "hg/lib/facetedTable.c:119", sep="_"), + ], + }, +} + +# --------------------------------------------------------------------------- +# LEVEL 4: reusable leaf groups. Types below reference these by key. +# --------------------------------------------------------------------------- + +FAMILIES = { + "numericFilter": { + "what": "Per-field numeric filter. Both spellings are live: the " + "lower-case dotted form and the older camel-case suffix " + "form. isComplexSetting() (hg/lib/trackDb.c:269) is the " + "authoritative list of these wildcard settings.", + "pattern": ["filter.", "Filter"], + "vars": [ + v("filter.", "float", "hg/inc/bigBedFilter.h:23", + note="Value, or 'min:max' colon pair."), + v("filter.Min", "float", "hg/inc/hui.h:_MIN"), + v("filter.Max", "float", "hg/inc/hui.h:_MAX"), + v("filterLimits.", "string", "hg/lib/trackDb.c:282", + note="trackDb-side bounds; cart values outside them are " + "dropped (hg/hgTracks/bigBedTrack.c:88)."), + v("filterByRange.", "bool", "hg/lib/trackDb.c:286"), + v("filterLabel.", "string", "hg/inc/bigBedFilter.h:28"), + v("filterPriority.", "float", "hg/inc/bigBedFilter.h:29"), + v("FilterLimits", "string", "hg/lib/trackDb.c:298"), + v("FilterPriority", "float", "hg/lib/trackDb.c:302"), + ], + }, + "textFilter": { + "what": "Per-field text filter, wildcard or regex.", + "vars": [ + v("filterText.", "string", "hg/inc/bigBedFilter.h:24"), + v("filterType.", "enum", "hg/inc/bigBedFilter.h:27", + values=["wildcard", "regexp"]), + v("FilterText", "string", "hg/lib/trackDb.c:300"), + v("FilterType", "enum", "hg/lib/trackDb.c:296"), + ], + }, + "filterBy": { + "what": "Multi-select filter on a categorical field. Value 'All' " + "means no filtering.", + "vars": [ + v("filterBy.", "list", "hg/lib/hui.c:4058", multi=True), + v("filterValues.", "string", "hg/inc/bigBedFilter.h:25", + note="trackDb-side value list."), + v("filterValuesDefault.", "string", + "hg/inc/bigBedFilter.h:26"), + v("doAdvanced", "bool", "hg/lib/hui.c:filterBySetCfgUiGuts", + note="Advanced filter box expanded."), + ], + }, + "highlightBy": { + "what": "Same shape as the filter family, but highlights instead of " + "hiding. Every filter* name has a highlight* twin.", + "vars": [ + v("highlightBy.", "list", "hg/lib/hui.c:4058", multi=True), + v("highlight.", "float", "hg/inc/bigBedFilter.h:64"), + v("highlightText.", "string", "hg/inc/bigBedFilter.h:65"), + v("highlightType.", "enum", "hg/inc/bigBedFilter.h:68"), + v("highlightLimits.", "string", "hg/lib/trackDb.c:...", + note="See isComplexSetting() for the full twin list."), + ], + }, + "score": { + "what": "The old score-based filters, offered by scoreCfgUi for bed " + "and friends.", + "vars": [ + v("scoreFilter", "int", "hg/lib/hui.c:scoreCfgUi", + tdb="scoreFilter"), + v("scoreFilterMin", "int", "hg/lib/hui.c:7268"), + v("scoreFilterMax", "int", "hg/lib/hui.c:7271"), + v("filterTopScorersOn", "bool", "hg/lib/hui.c:7301"), + v("filterTopScorersCt", "int", "hg/lib/hui.c:7307"), + v("minGrayLevel", "int", "hg/inc/hui.h:MIN_GRAY_LEVEL", + tdb="minGrayLevel"), + ], + }, + "cds": { + "what": "Codon and base coloring, offered for every type that has " + "aligned or CDS-bearing items. hg/lib/hui.c:baseColorDropLists.", + "vars": [ + v("baseColorDrawOpt", "enum", "hg/inc/hui.h:BASE_COLOR_VAR_SUFFIX", + values=["none", "genomicCodons", "itemCodons", "diffCodons", + "itemBases", "diffBases"]), + v("codonNumbering", "bool", "hg/inc/hui.h:CODON_NUMBERING_SUFFIX"), + v("showDiffBasesAllScales", "bool", + "hg/inc/hui.h:SHOW_DIFF_BASES_ALL_SCALES"), + v("baseColorUseCds", "string", "hg/inc/hui.h:BASE_COLOR_USE_CDS", + note="trackDb setting; read through cartOrTdb."), + v("baseColorUseSequence", "string", + "hg/inc/hui.h:BASE_COLOR_USE_SEQUENCE", + note="trackDb setting; read through cartOrTdb."), + ], + }, + "indel": { + "what": "Indel display, alignment types. " + "hg/lib/hui.c:indelShowOptionsWithNameExt.", + "vars": [ + v("indelDoubleInsert", "bool", "hg/inc/hui.h:INDEL_DOUBLE_INSERT"), + v("indelQueryInsert", "bool", "hg/inc/hui.h:INDEL_QUERY_INSERT"), + v("indelPolyA", "bool", "hg/inc/hui.h:INDEL_POLY_A"), + ], + }, + "label": { + "what": "Which label to draw. Legacy tracks each grew their own " + "checkbox set, which is why the same idea appears under so " + "many names. hg/lib/hui.c:labelCfgUi is the modern one.", + "vars": [ + v("label", "list", "hg/lib/hui.c:labelMakeCheckBox", multi=True, + tdb="labelFields", + note="Modern bigBed form: one entry per chosen field."), + v("label.gene", "bool", "hg/hgTracks/retroGene.c:121"), + v("label.acc", "bool", "hg/hgTracks/transMapTracks.c:48"), + v("label.orgCommon", "bool", "hg/hgTracks/transMapTracks.c:50"), + v("accLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1511"), + v("geneLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1510"), + v("posLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1513"), + v("sprotLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1512"), + ], + }, + "gencodeShow": { + "what": "GENCODE / knownGene transcript-set filters.", + "vars": [ + v("show.set", "enum", "hg/lib/hui.c:newGencodeShowOptions"), + v("show.noncoding", "bool", "hg/lib/hui.c:newGencodeShowOptions"), + v("show.pseudo", "bool", "hg/lib/hui.c:newGencodeShowOptions"), + v("show.spliceVariants", "bool", + "hg/lib/hui.c:newGencodeShowOptions"), + v("show.comprehensive", "bool", + "hg/hgTrackUi/hgTrackUi.c:1747"), + v("hideNoncoding", "bool", "hg/inc/hui.h:HIDE_NONCODING_SUFFIX"), + v("maxTrans", "int", "hg/lib/hui.c:gencodeMaxTransControl"), + ], + }, + "decorator": { + "what": "A decorator is a nested namespace inside the track: " + ".decorator... " + "hg/lib/decoratorUi.c gins up a fake tdb so the filter " + "families above work unchanged inside it.", + "prefix": "decorator..", + "vars": [ + v("decorator..blockMode", "enum", + "hg/lib/decoratorUi.c:21", + values=["Hide", "Overlay", "Adjacent"], default="Overlay"), + v("decorator..glyphMode", "enum", + "hg/lib/decoratorUi.c:23", + values=["Hide", "Overlay", "Adjacent"], default="Overlay"), + v("decorator..Overlaytoggle", "bool", + "hg/lib/decoratorUi.c:19", + note="Draw labels for blocks in overlay mode."), + v("decorator..maxLabelBases", "int", + "hg/lib/decoratorUi.c:26", default="200000"), + v("decorator..filterBy.", "list", + "hg/lib/decoratorUi.c:176", multi=True, + note="Whole filterBy family nests here."), + ], + }, + "species": { + "what": "Per-species on/off, used by maf/wigMaf and by chain/net " + "cross-species coloring.", + "vars": [ + v("", "bool", "hg/lib/hui.c:isSpeciesOn", + note="One var per species in the maf, name is the db or " + "species name itself."), + v("speciesOrder", "string", "hg/hgc/mafClick.c:609"), + ], + }, +} + +# --------------------------------------------------------------------------- +# LEVEL 3: the type layer. Keyed by eCfgType where one exists +# (hg/inc/trackDb.h:439) plus the types that fall through cfgByCfgType. +# --------------------------------------------------------------------------- + +TYPES = { + "wig": { + "cfgType": "cfgWig", + "tdbTypes": ["wig", "bigWig", "bedGraph", "mathWig", "instaPort"], + "cfgUi": "hg/lib/hui.c:wigCfgUi", + "cart": "hg/lib/wiggleCart.c", + "families": [], + "vars": [ + v("minY", "float", "hg/inc/wiggle.h:MIN_Y", tdb="viewLimits"), + v("maxY", "float", "hg/inc/wiggle.h:MAX_Y", tdb="viewLimits"), + v("autoScale", "enum", "hg/inc/wiggle.h:AUTOSCALE", + values=["on", "off", "group", "cumulative"], + tdb="autoScaleDefault"), + v("alwaysZero", "enum", "hg/inc/wiggle.h:ALWAYSZERO", + values=["on", "off"]), + v("lineBar", "enum", "hg/inc/wiggle.h:LINEBAR", + values=["Bar", "Points"], tdb="graphTypeDefault"), + v("transformFunc", "enum", "hg/inc/wiggle.h:TRANSFORMFUNC", + values=["NONE", "LOG"]), + v("negateValues", "bool", "hg/inc/wiggle.h:DONEGATIVEMODE"), + v("sequenceLogo", "bool", "hg/inc/wiggle.h:DOSEQUENCELOGOMODE"), + v("horizGrid", "enum", "hg/inc/wiggle.h:HORIZGRID", + values=["on", "off"], tdb="gridDefault"), + v("yLineOnOff", "enum", "hg/inc/wiggle.h:YLINEONOFF", + values=["on", "off"]), + v("yLineMark", "float", "hg/inc/wiggle.h:YLINEMARK"), + v("smoothingWindow", "enum", "hg/inc/wiggle.h:SMOOTHINGWINDOW", + values=["off", "2", "3", "4", "...", "16"]), + v("windowingFunction", "enum", + "hg/inc/wiggle.h:WINDOWINGFUNCTION", + values=["mean+whiskers", "maximum", "mean", "minimum", "sum"]), + v("aggregate", "enum", "hg/inc/wiggle.h:AGGREGATE", + values=["none", "transparentOverlay", "solidOverlay", + "stacked", "add", "subtract"], + note="Container-level, but readable at leaf level too."), + v("viewFunc", "enum", "hg/inc/wiggle.h:VIEWFUNC", + values=["showAll", "addAll", "subtractAll"]), + v("missingMethod", "enum", "hg/lib/hui.c:6257", + note="How to render gaps in the data."), + v("heightPer", "int", "hg/inc/wiggle.h:HEIGHTPER", default="128"), + ], + "tdbOnly": ["viewLimits", "viewLimitsMax", "defaultViewLimits", + "minLimit", "maxLimit", "maxHeightPixels", "gridDefault", + "autoScaleDefault", "graphType", "graphTypeDefault", + "spanList"], + }, + "bedScore": { + "cfgType": "cfgBedScore", + "tdbTypes": ["bed", "bigBed", "bed +", "bigNarrowPeak", "broadPeak"], + "cfgUi": "hg/lib/hui.c:bedScoreCfgUi", + "families": ["score", "numericFilter", "textFilter", "filterBy", + "highlightBy", "label", "cds", "decorator"], + "vars": [ + v("colorField", "string", "hg/lib/hui.c:colorFieldsCfgUi", + tdb="colorByStrand"), + v("scoreLabel", "string", "hg/inc/hui.h:SCORE_LABEL"), + ], + "tdbOnly": ["noScoreFilter", "scoreMin", "labelFields", + "defaultLabelFields"], + }, + "bedFilt": { + "cfgType": "cfgBedFilt", + "tdbTypes": ["bed (mrna-style filters)"], + "cfgUi": "hg/lib/hui.c:bedFiltCfgUi", + "families": [], + "vars": [ + v("", "string", "hg/lib/hui.c:bedFiltCfgUi", + note="One var per filter declared in the track's mrnaUiData " + "(hg/hgTracks/bedTrack.c:427)."), + v("Type", "enum", "hg/hgTracks/bedTrack.c:434", + values=["include", "exclude"]), + v("Logic", "enum", "hg/hgTracks/bedTrack.c:441", + values=["and", "or"]), + ], + }, + "peak": { + "cfgType": "cfgPeak", + "tdbTypes": ["encodePeak", "narrowPeak", "broadPeak", "gappedPeak"], + "cfgUi": "hg/lib/hui.c:encodePeakCfgUi", + "families": ["score", "numericFilter"], + "vars": [ + v("signalFilter", "float", "hg/inc/hui.h:SIGNAL_FILTER"), + v("signalFilterLimits", "string", "hg/inc/hui.h:_LIMITS"), + v("pValueFilter", "float", "hg/inc/hui.h:PVALUE_FILTER"), + v("qValueFilter", "float", "hg/inc/hui.h:QVALUE_FILTER"), + ], + }, + "genePred": { + "cfgType": "cfgGenePred", + "tdbTypes": ["genePred", "bigGenePred"], + "cfgUi": "hg/lib/hui.c:genePredCfgUi", + "families": ["cds", "indel", "label", "gencodeShow", "numericFilter", + "filterBy", "score", "decorator"], + "vars": [ + v("type", "enum", "hg/lib/hui.c:genePredCfgUi", + note="Which of several gene ID sources to label with."), + v("geneClasses", "string", "hg/inc/hui.h:GENEPRED_CLASS_VAR", + note="trackDb-declared class list; per-class colors are the " + "trackDb settings gClass_, not cart vars."), + v("itemClassTbl", "string", "hg/inc/hui.h:GENEPRED_CLASS_TBL"), + ], + }, + "psl": { + "cfgType": "cfgPsl", + "tdbTypes": ["psl", "bigPsl", "psl xeno ", "chain (via snake)"], + "cfgUi": "hg/lib/hui.c:pslCfgUi", + "families": ["cds", "indel", "score", "label"], + "vars": [ + v("color", "enum", "hg/lib/hui.c:crossSpeciesCfgUi", + values=["on", "off"], + note="Chromosome coloring for cross-species psl. Default " + "'on' unless trackDb colorChromDefault off."), + v("showPatentSequences", "bool", + "hg/inc/hui.h:SHOW_PATENT_SEQUENCES_SUFFIX"), + v("chromFilter", "string", + "hg/hgTracks/pslTrack.c:connectedLfFromPslsInRange"), + v("pslSequenceBases", "string", "hg/inc/hui.h:PSL_SEQUENCE_BASES", + default="no"), + ], + }, + "chain": { + "cfgType": "cfgChain", + "tdbTypes": ["chain", "bigChain"], + "cfgUi": "hg/lib/hui.c:chainCfgUi", + "families": ["score"], + "vars": [ + v("chainColor", "enum", "hg/inc/chainCart.h:OPT_CHROM_COLORS", + values=["Chromosome", "Normalized Score", "Black"]), + v("chromFilter", "string", "hg/inc/chainCart.h:OPT_CHROM_FILTER", + note="Restrict to chains against one query chrom."), + v("color", "enum", "hg/lib/hui.c:chainCfgUi", + values=["on", "off"], + note="Cross-species chromosome coloring, shared with psl."), + ], + "tdbOnly": ["chainNormScoreAvailable"], + }, + "net": { + "cfgType": "cfgNetAlign", + "tdbTypes": ["netAlign"], + "cfgUi": "hg/lib/hui.c:netAlignCfgUi", + "families": [], + "vars": [ + v("netColor", "enum", "hg/inc/netCart.h:NET_COLOR", + values=["Chromosome", "Gray scale"]), + v("netLevel", "enum", "hg/inc/netCart.h:NET_LEVEL", + values=["All levels", "level 1 only", "level 2 only", + "level 3 only", "level 4 only", "level 5 only", + "level 6 only"]), + v("netTopOnly", "bool", "hg/inc/hui.h:NET_OPT_TOP_ONLY"), + ], + }, + "wigMaf": { + "cfgType": "cfgWigMaf", + "tdbTypes": ["wigMaf", "bigMaf", "maf"], + "cfgUi": "hg/lib/hui.c:wigMafCfgUi", + "families": ["species", "wig (embedded conservation wiggle)"], + "vars": [ + v("mafDot", "bool", "hg/inc/hui.h:MAF_DOT_VAR", + note="Show dots for matching bases."), + v("mafChain", "bool", "hg/inc/hui.h:MAF_CHAIN_VAR", + note="Display chains between blocks."), + v("mafShowSnp", "bool", "hg/inc/hui.h:MAF_SHOW_SNP"), + v("mafGenePred", "string", "hg/inc/hui.h:MAF_GENEPRED_VAR", + note="Gene track used for codon translation."), + v("mafFrame", "enum", "hg/inc/hui.h:MAF_FRAMING_VAR"), + v("codons", "enum", "hg/hgTracks/wigMafTrack.c:2085"), + v("frames", "string", "hg/hgTracks/wigMafTrack.c:2079"), + v("baseColors", "string", "hg/hgTracks/wigMafTrack.c:2405"), + v("baseColorsOffset", "int", + "hg/hgTracks/wigMafTrack.c:2407"), + v(".", "varies", + "hg/hgTracks/wigMafTrack.c:2760", + note="The conservation wiggle is configured as a nested " + "namespace under the wigMaf track."), + ], + }, + "bam": { + "cfgType": "cfgBam", + "tdbTypes": ["bam", "cram"], + "cfgUi": "hg/lib/hui.c:bamCfgUi", + "families": ["cds", "indel", "wig (when bamWigMode is on)"], + "vars": [ + v("pairEndsByName", "bool", "hg/inc/hui.h:BAM_PAIR_ENDS_BY_NAME"), + v("showNames", "bool", "hg/inc/hui.h:BAM_SHOW_NAMES"), + v("minAliQual", "int", "hg/inc/hui.h:BAM_MIN_ALI_QUAL", + default="0"), + v("bamColorMode", "enum", "hg/inc/hui.h:BAM_COLOR_MODE", + values=["gray", "strand", "tag", "off"], default="strand"), + v("bamGrayMode", "enum", "hg/inc/hui.h:BAM_GRAY_MODE", + values=["aliQual", "baseQual", "unpaired"], default="aliQual"), + v("bamColorTag", "string", "hg/inc/hui.h:BAM_COLOR_TAG", + default="YC"), + v("bamWigMode", "bool", "hg/inc/hui.h:BAMWIG_MODE", + note="Draw coverage as a wiggle; pulls in the wig group."), + ], + }, + "vcf": { + "cfgType": "cfgVcf", + "tdbTypes": ["vcfTabix", "vcf", "vcfPhasedTrio"], + "cfgUi": "hg/lib/vcfUi.c:vcfCfgUi", + "families": ["filterBy"], + "vars": [ + v("hapClusterEnabled", "bool", "hg/inc/vcfUi.h:16"), + v("hapClusterHeight", "int", "hg/inc/vcfUi.h:13"), + v("hapClusterMethod", "enum", "hg/inc/vcfUi.h:17", + values=["centerWeighted", "fileOrder", "treeFile"]), + v("hapClusterColorBy", "enum", "hg/inc/vcfUi.h:23", + values=["altOnly", "function", "refAlt", "base"]), + v("hapClusterTreeAngle", "enum", "hg/inc/vcfUi.h:30", + values=["triangle", "rectangle"]), + v("sampleColorFile", "string", "hg/inc/vcfUi.h:35"), + v("applyMinQual", "bool", "hg/inc/vcfUi.h:40"), + v("minQual", "float", "hg/inc/vcfUi.h:44"), + v("minFreq", "float", "hg/inc/vcfUi.h:52"), + v("excludeFilterValues", "list", "hg/inc/vcfUi.h:49", multi=True), + v("showHardyWeinberg", "bool", "hg/inc/vcfUi.h:38"), + v("vcfSampleOrder", "string", "hg/inc/vcfUi.h:57", + note="Drag-and-drop sample order, comma separated."), + v("doDefaultLabel", "bool", "hg/inc/vcfUi.h:59"), + v("doAliasLabel", "bool", "hg/inc/vcfUi.h:60"), + v("hideParents", "bool", "hg/inc/vcfUi.h:61"), + v("sortChildBelow", "bool", "hg/inc/vcfUi.h:63"), + v("vcfPhasedColorBy", "enum", "hg/inc/vcfUi.h:65", + values=["mendelDiff", "deNovo", "function", "noColor"]), + v("centerVariantChrom", "hidden", "hg/lib/vcfUi.c:33", + note="Haplotype-sorting anchor. Position state stored on the " + "track, which is unusual and worth flagging in a " + "rewrite."), + v("centerVariantPos", "hidden", "hg/lib/vcfUi.c:35"), + v("centerVariantName", "hidden", "hg/lib/vcfUi.c:39"), + ], + }, + "snake": { + "cfgType": "cfgSnake", + "tdbTypes": ["halSnake", "chain (snake mode)", "pslSnake"], + "cfgUi": "hg/lib/snakeUi.c:snakeCfgUi", + "families": ["score"], + "vars": [ + v("showSnpWidth", "int", "hg/inc/snakeUi.h:12"), + v("colorBy", "enum", "hg/inc/snakeUi.h:24", + values=["byStrand", "byChromosome", "none"]), + v("chromFilter", "string", + "hg/hgTracks/halSnakeTrack.c:snakeLoadItems"), + v("coalescent", "string", "hg/hgTracks/halSnakeTrack.c:1764", + note="HAL only."), + v("color", "enum", "hg/hgTracks/halSnakeTrack.c:snakeMethods"), + ], + }, + "long": { + "cfgType": "cfgLong", + "tdbTypes": ["longTabix"], + "cfgUi": "hg/lib/longRange.c:longRangeCfgUi", + "families": [], + "vars": [ + v("heightPer", "int", "hg/inc/longRange.h:14", default="200"), + v("minScore", "float", "hg/inc/longRange.h:18", default="0"), + ], + }, + "interact": { + "cfgType": "cfgInteract", + "tdbTypes": ["interact", "bigInteract"], + "cfgUi": "hg/lib/interactUi.c:interactCfgUi", + "families": ["score", "filterBy"], + "vars": [ + v("heightPer", "int", "hg/inc/interactUi.h:9", default="200"), + v("minScore", "float", "hg/inc/interactUi.h:13"), + v("draw", "enum", "hg/inc/interactUi.h:38", + values=["line", "ellipse", "curve"]), + v("dashes", "bool", "hg/inc/interactUi.h:35", + note="Dash the line to show direction."), + v("endsVisible", "enum", "hg/inc/interactUi.h:44", + values=["two", "one", "any"]), + v("cluster", "enum", "hg/inc/interactUi.h:50", + values=["none", "source", "target"]), + v("detailsBoxesEnabled", "bool", "hg/inc/interactUi.h:31"), + ], + "tdbOnly": ["interactDirectional", "offsetSource", "offsetTarget", + "clusterSource", "clusterTarget", "interactUp"], + }, + "hic": { + "cfgType": "cfgHic", + "tdbTypes": ["hic"], + "cfgUi": "hg/lib/hicUi.c:hicCfgUi", + "families": [], + "vars": [ + v("drawMode", "enum", "hg/inc/hicUi.h:31", + values=["triangle", "square", "arc"]), + v("inverted", "bool", "hg/inc/hicUi.h:36"), + v("normalization", "string", "hg/inc/hicUi.h:37"), + v("resolution", "string", "hg/inc/hicUi.h:38"), + v("autoscale", "bool", "hg/inc/hicUi.h:39", + note="Lower case, unlike the wig autoScale."), + v("max", "float", "hg/inc/hicUi.h:40", tdb="saturationScore"), + v("color", "color", "hg/inc/hicUi.h:42", default="#ff0000"), + v("bgColor", "color", "hg/inc/hicUi.h:43", default="#ffffff"), + v("maxDistance", "int", "hg/inc/hicUi.h:47", + tdb="hicDistanceMax"), + v("minDistance", "int", "hg/inc/hicUi.h:48", + tdb="hicDistanceMin"), + v("hicArcLimit", "int", "hg/inc/hicUi.h:50"), + v("hicArcLimitEnabled", "bool", "hg/inc/hicUi.h:51"), + ], + }, + "barChart": { + "cfgType": "cfgBarChart", + "tdbTypes": ["barChart", "bigBarChart"], + "cfgUi": "hg/lib/barChartUi.c:barChartCfgUi", + "families": ["score", "filterBy", "label"], + "vars": [ + v("colorScheme", "enum", "hg/inc/barChartUi.h:13", + values=["rainbow", "user"]), + v("logTransform", "bool", "hg/inc/barChartUi.h:22"), + v("maxViewLimit", "float", "hg/inc/barChartUi.h:29", + tdb="maxLimit"), + v("categories", "list", "hg/inc/barChartUi.h:38", multi=True, + note="Which categories to show; 'All' means every one."), + v("noWhiteout", "bool", "hg/inc/barChartUi.h:58"), + ], + "tdbOnly": ["barChartBars", "barChartLabel", "barChartColors", + "barChartCategoryUrl", "barChartUnit", "barChartMetric", + "barChartMaxSize", "barChartSizeWindows", + "barChartBarMinWidth", "barChartBarMinPadding", + "barChartLimit"], + }, + "lolly": { + "cfgType": "cfgLollipop", + "tdbTypes": ["bigLolly"], + "cfgUi": "hg/lib/hui.c:lollyCfgUi", + "families": ["score", "numericFilter", "filterBy", "label"], + "vars": [ + v("heightPer", "int", "hg/lib/hui.c:lollyCfgUi"), + v("autoScale", "enum", "hg/lib/hui.c:lollyCfgUi", + values=["on", "off"]), + v("minY", "float", "hg/lib/hui.c:lollyCfgUi"), + v("maxY", "float", "hg/lib/hui.c:lollyCfgUi"), + v("popMethod", "enum", "hg/lib/hui.c:lollyCfgUi", + tdb="popMethod"), + ], + }, + "bigDbSnp": { + "cfgType": "cfgBigDbSnp", + "tdbTypes": ["bigDbSnp"], + "cfgUi": "hg/lib/hui.c:bigDbSnpCfgUi", + "families": ["filterBy", "label"], + "vars": [ + v("minMaf", "float", "hg/lib/hui.c:4954"), + v("freqProj", "enum", "hg/lib/hui.c:freqSourceSelect", + note="Which frequency project supplies MAF."), + v("label.rsId", "bool", "hg/hgTracks/variation.c:2712"), + v("label.majMin", "bool", "hg/hgTracks/variation.c:2723"), + v("label.refAlt", "bool", "hg/hgTracks/variation.c:2715"), + v("label.func", "bool", "hg/hgTracks/variation.c:2737"), + v("label.maf", "bool", "hg/hgTracks/variation.c:2730"), + v("geneTrack", "string", "hg/lib/hui.c:4881"), + v("geneTracks", "list", "hg/lib/hui.c:4875", multi=True), + ], + }, + "bigRmsk": { + "cfgType": "cfgBigRmsk", + "tdbTypes": ["bigRmsk"], + "cfgUi": "hg/lib/hui.c:bigRmskCfgUi", + "families": [], + "prefix": "bigrmsk.", + "vars": [ + v("bigrmsk.showUnalignedExtents", "bool", + "hg/inc/bigRmskUi.h:10"), + v("bigrmsk.showLabels", "bool", "hg/inc/bigRmskUi.h:14"), + v("bigrmsk.origPackViz", "bool", "hg/inc/bigRmskUi.h:18"), + v("bigrmsk.nameFilter", "string", "hg/inc/bigRmskUi.h:22", + default="*"), + v("bigrmsk.regexpFilter", "string", "hg/inc/bigRmskUi.h:26"), + ], + }, + "gtexGene": { + "cfgType": "(cfgBedScore plus gtexGeneUi)", + "tdbTypes": ["bed 12 + (gtexGene*)"], + "cfgUi": "hg/lib/gtexUi.c:gtexGeneUi", + "families": ["score"], + "vars": [ + v("colorScheme", "enum", "hg/inc/gtexUi.h:9", + values=["rainbow", "gtex"]), + v("logTransform", "bool", "hg/inc/gtexUi.h:18"), + v("maxViewLimit", "float", "hg/inc/gtexUi.h:23"), + v("samples", "enum", "hg/inc/gtexUi.h:29", + values=["all", "sex", "age"]), + v("comparison", "enum", "hg/inc/gtexUi.h:39", + values=["mirror", "difference"]), + v("graphType", "enum", "hg/inc/gtexUi.h:45", + values=["raw", "normalized"]), + v("tissues", "list", "hg/inc/gtexUi.h:51", multi=True), + v("codingOnly", "bool", "hg/inc/gtexUi.h:54"), + v("showExons", "bool", "hg/inc/gtexUi.h:58"), + v("noWhiteout", "bool", "hg/inc/gtexUi.h:62"), + v("label", "enum", "hg/inc/gtexUi.h:66", + values=["name", "accession", "both"]), + ], + }, + "gtexEqtlCluster": { + "cfgType": "(cfgBedScore plus gtexEqtlClusterUi)", + "tdbTypes": ["bed 9 + (gtexEqtlCluster*)"], + "cfgUi": "hg/lib/gtexUi.c:gtexEqtlClusterUi", + "families": ["score"], + "vars": [ + v("effect", "float", "hg/inc/gtexUi.h:74"), + v("prob", "float", "hg/inc/gtexUi.h:76"), + v("gene", "string", "hg/inc/gtexUi.h:78"), + v("tissueColor", "bool", "hg/inc/gtexUi.h:79"), + v("tissues", "list", "hg/inc/gtexUi.h:51", multi=True), + ], + }, + "expRatio": { + "cfgType": "(falls through cfgByCfgType)", + "tdbTypes": ["expRatio", "array"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:expRatioUi", + "families": [], + "vars": [ + v("color", "enum", "hg/hgTrackUi/hgTrackUi.c:1360", + note="Red/green vs blue/yellow etc."), + v("type", "enum", "hg/hgTracks/expRatioTracks.c:lfsFromAffyBed"), + v("combine", "enum", "hg/lib/microarray.c:1167"), + v("subset", "enum", "hg/lib/microarray.c:1174"), + v("expDrawExons", "bool", "hg/hgTrackUi/hgTrackUi.c:1347"), + v("heightPer", "int", "hg/hgTrackUi/hgTrackUi.c:2026"), + ], + }, + "sample": { + "cfgType": "(falls through cfgByCfgType)", + "tdbTypes": ["sample"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:genericWiggleUi", + "families": [], + "vars": [ + v("heightPer", "int", "hg/hgTracks/sampleTracks.c:sampleTotalHeight"), + v("min.cutoff", "float", "hg/hgTrackUi/hgTrackUi.c:2029"), + v("max.cutoff", "float", "hg/hgTrackUi/hgTrackUi.c:2030"), + v("linear.interp", "enum", "hg/hgTrackUi/hgTrackUi.c:2027"), + v("interp.gap", "int", "hg/hgTrackUi/hgTrackUi.c:2031"), + v("fill", "bool", "hg/hgTrackUi/hgTrackUi.c:2028"), + v("anti.alias", "bool", "hg/hgTracks/sampleTracks.c:272"), + ], + }, + "chromGraph": { + "cfgType": "(falls through cfgByCfgType)", + "tdbTypes": ["chromGraph"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:chromGraphUi", + "families": [], + "note": "Exception: names are cgs__, prefix first. See " + "the exceptions section.", + "vars": [ + v("pixels", "int", "hg/lib/chromGraph.c:chromGraphVarName", + sep="cgs__"), + v("minVal", "float", "hg/lib/chromGraph.c:301", + sep="cgs__"), + v("maxVal", "float", "hg/lib/chromGraph.c:303", + sep="cgs__"), + v("maxGapToFill", "int", "hg/lib/chromGraph.c:299", + sep="cgs__"), + ], + }, + "factorSource": { + "cfgType": "(falls through cfgByCfgType)", + "tdbTypes": ["factorSource"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:factorSourceUi", + "families": ["score", "filterBy"], + "vars": [ + v("highlightMotifs", "bool", "hg/hgTrackUi/hgTrackUi.c:2778"), + v("showCellAbbrevs", "bool", "hg/hgTrackUi/hgTrackUi.c:2789"), + v("showExpCounts", "bool", "hg/hgTrackUi/hgTrackUi.c:2785"), + ], + }, + "ld": { + "cfgType": "(name/type special case)", + "tdbTypes": ["ld2", "hapmapLd*", "rertyHumanDiversityLd"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:ldUi", + "families": [], + "note": "All underscore-separated, one of the oldest var sets.", + "vars": [ + v("_val", "enum", "hg/hgTracks/variation.c:ldDrawItems", sep="_", + values=["rsquared", "dprime", "lod"]), + v("_trm", "bool", "hg/hgTracks/variation.c:ldDrawItems", sep="_", + note="Trim to triangle."), + v("_inv", "bool", "hg/hgTracks/variation.c:ldDrawItems", sep="_", + note="Invert the display."), + v("_pos", "color", "hg/hgTracks/variation.c:ldShadesInit", + sep="_"), + v("_out", "enum", "hg/hgTracks/variation.c:getOutlineColor", + sep="_"), + v("_gap", "bool", "hg/hgTracks/variation.c:ldDrawDense", sep="_"), + ], + }, + "gvf": { + "cfgType": "(falls through cfgByCfgType)", + "tdbTypes": ["gvf"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:gvUi", + "families": [], + "vars": [ + v("_", "bool", "hg/hgTracks/gvfTrack.c:gvfItemName", + sep="_", + note="One per variant origin: _germ _som _dnovo _bip _mat " + "_pat _unip _unk."), + ], + }, + "snp125": { + "cfgType": "(name special case, snpVersion >= 125)", + "tdbTypes": ["snp125 .. snp15x"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:snp125Ui", + "families": [], + "vars": [ + v("include_", "list", + "hg/cgilib/snp125Ui.c:605", multi=True, + note="Attribute is one of molType class valid func locType " + "exceptions bitfields. Values are the kept categories."), + v("colorSource", "enum", "hg/cgilib/snp125Ui.c:687", + values=["locType", "class", "valid", "func", "molType", + "exceptions", "bitfields", "alleleFreq"]), + v("", "color", + "hg/hgTrackUi/hgTrackUi.c:snp125RemoveColorVars", + note="One color var per attribute value, e.g. " + ".funcMissense. Nested leaf level keyed by " + "attribute then value."), + v("minAvHet", "float", "hg/hgTrackUi/hgTrackUi.c:416"), + v("maxWeight", "int", "hg/hgTrackUi/hgTrackUi.c:424"), + v("minSubmitters", "int", "hg/hgTrackUi/hgTrackUi.c:440"), + v("minMinorAlFreq", "float", "hg/hgTrackUi/hgTrackUi.c:444"), + v("maxMinorAlFreq", "float", "hg/hgTrackUi/hgTrackUi.c:448"), + v("minAlFreq2N", "int", "hg/hgTrackUi/hgTrackUi.c:455"), + v("extendedNames", "bool", "hg/hgTrackUi/hgTrackUi.c:726"), + v("allelesDbSnpStrand", "bool", "hg/hgTrackUi/hgTrackUi.c:745"), + ], + }, + "blast": { + "cfgType": "(name special case)", + "tdbTypes": ["blastHg*KG, blastDm*, blastSacCer1SG, mrnaMap*, " + "mrnaXeno*"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:blastUi", + "families": ["label", "cds"], + "vars": [ + v("cmode", "enum", "hg/hgTracks/simpleTracks.c:blastColor", + note="Color mode: black, by identity, by species."), + ], + }, + "pubs": { + "cfgType": "(name special case, startsWith pubs)", + "tdbTypes": ["pubs*"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:pubsUi", + "families": [], + "vars": [ + v("pubsFilterKeywords", "string", + "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"), + v("pubsFilterYear", "string", + "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"), + v("pubsFilterPublisher", "string", + "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"), + v("pubsColorBy", "enum", "hg/hgTracks/pubsTracks.c:pubsMakeExtra"), + ], + }, + "transMap": { + "cfgType": "(name special case, transMapAln*)", + "tdbTypes": ["psl (transMap)"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:transMapUI", + "families": ["label", "cds", "indel"], + "vars": [], + }, + "retroGene": { + "cfgType": "(name special case, ucscRetro*, retroMrnaInfo*)", + "tdbTypes": ["psl (retro)"], + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:retroGeneUI", + "families": ["label", "cds", "indel"], + "vars": [], + }, + "mrna": { + "cfgType": "(name special case: mrna, est, xenoMrna, intronEst, ...)", + "tdbTypes": ["psl"], + "cfgUi": "hg/lib/hui.c:mrnaCfgUi", + "families": ["cds", "indel", "bedFilt"], + "vars": [], + }, +} + +# --------------------------------------------------------------------------- +# LEVEL 3b: tracks whose vars are written as literals rather than composed +# from tdb->track. They still sit under ., so they belong in the +# hierarchy, but grep for the suffix alone will not find them. +# --------------------------------------------------------------------------- + +BY_TRACK_NAME = { + "stsMap": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:stsMapUi", + "vars": [ + v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:91", + values=["blue", "red", "green", "black"]), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:91"), + ], + }, + "stsMapMouseNew / stsMapRat": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:stsMapMouseUi", + "vars": [ + v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:101"), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:101"), + ], + }, + "cbr_waba": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:cbrWabaUi", + "vars": [ + v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:1223"), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1223"), + v("start", "int", "hg/hgTrackUi/hgTrackUi.c:1223"), + v("end", "int", "hg/hgTrackUi/hgTrackUi.c:1223"), + ], + }, + "fishClones": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:fishClonesUi", + "vars": [ + v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:1236"), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1236"), + ], + }, + "recombRate / recombRateRat / recombRateMouse": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:recombRateUi", + "vars": [v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1246")], + }, + "cghNci60": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:cghNci60Ui", + "vars": [ + v("color", "enum", "hg/hgTrackUi/hgTrackUi.c:1270", + values=["rg", "rb", "gr"]), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1270"), + ], + }, + "rosetta": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:rosettaUi", + "vars": [ + v("et", "enum", "hg/hgTrackUi/hgTrackUi.c:1456"), + v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1456"), + ], + }, + "switchDbTss": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:switchDbScoreUi", + "vars": [ + v("scoreFilter", "int", "hg/hgTrackUi/hgTrackUi.c:1475", + default="10"), + v("pseudo", "bool", "hg/hgTrackUi/hgTrackUi.c:1475"), + ], + }, + "affyTranscriptome": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:affyTranscriptomeUi", + "vars": [ + v("fill", "bool", "hg/hgTrackUi/hgTrackUi.c:2479"), + v("heightPer", "int", "hg/hgTrackUi/hgTrackUi.c:2479", + default="100"), + ], + }, + "ancientR": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:ancientRUi", + "vars": [v("minLength", "int", "hg/hgTrackUi/hgTrackUi.c:2500", + default="50")], + }, + "affyTransfrags": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:affyTransfragUi", + "vars": [ + v("skipDups", "bool", "hg/hgTrackUi/hgTrackUi.c:2511"), + v("skipPseudos", "bool", "hg/hgTrackUi/hgTrackUi.c:2511"), + ], + }, + "oreganno": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:oregannoUi", + "vars": [ + v("hgvs", "bool", "hg/hgTrackUi/hgTrackUi.c:952", + note="Via labelMakeCheckBox, which is generic: the caller " + "picks the suffix."), + v("common", "bool", "hg/hgTrackUi/hgTrackUi.c:953"), + ], + "note": "Its type filters are NOT track-scoped: they use the global " + "names in oregannoTypeString[].", + }, + "lrg": { + "cfgUi": "hg/lib/hui.c:lrgCfgUi", + "vars": [], + "note": "cds + indel families only.", + }, + "gene ID label configs": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:geneIdConfig and friends", + "vars": [ + v("label", "list", "hg/hgTrackUi/hgTrackUi.c:geneIdConfig", + multi=True, + note="Shared shape for refGene, ncbiGene, xenoRefGene, " + "knownGene, ensGene, ensGeneNonCoding, vegaGeneComposite, " + "rgdGene2, hg17Kg, refSeqComposite, omimGene, omimGene2, " + "omimLocation, ucscRetro*, transMapAln*. Each supplies a " + "different value list."), + ], + }, + "transRegCode": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c:transRegCodeUi", + "vars": [], + "note": "Explanatory text only, no controls.", + }, + "wikiTrack / quickLiftChain / hgPcrResult / cgapSage": { + "cfgUi": "hg/hgTrackUi/hgTrackUi.c", + "vars": [], + "note": "No cart vars of their own at UI time.", + }, +} + +# --------------------------------------------------------------------------- +# Vars that configure exactly one track but are NOT scoped by track name. +# These are the ones an accessor layer cannot generate from tdb->track. +# --------------------------------------------------------------------------- + +GLOBAL_BUT_TRACK_SPECIFIC = [ + v("dbRIP.genoRegion", "enum", "hg/inc/hui.h:GENO_REGION", sep="", + default="any", note="retroposons / dbRIP* tracks. 'dbRIP' is a " + "pseudo-namespace, not a track name."), + v("dbRIP.polySource", "enum", "hg/inc/hui.h:POLY_SOURCE", sep="", + default="don't care"), + v("dbRIP.polySubFamily", "enum", "hg/inc/hui.h:POLY_SUBFAMILY", sep="", + default="any"), + v("dbRIP.ethnicGroup", "enum", "hg/inc/hui.h:ETHNIC_GROUP", sep="", + default="any"), + v("dbRIP.ethnicExcInc", "enum", "hg/inc/hui.h:ETHNIC_GROUP_EXCINC", + sep="", values=["include", "exclude"]), + v("tfbsConsSitesCutoff", "float", "hg/inc/hui.h:TFBS_SITES_CUTOFF", + sep="", default="2.33", note="tfbsConsSites track."), + v("ucsfdemoER", "enum", "hg/inc/hui.h:UCSF_DEMO_ER", sep="", + default="no filter", note="CGHBreastCancerUCSF track."), + v("ucsfdemoPR", "enum", "hg/inc/hui.h:UCSF_DEMO_PR", sep="", + default="no filter"), + v("hapmapSnps_popCount", "enum", "hg/inc/hui.h:HAP_POP_COUNT", sep=""), + v("hapmapSnps_isMixed", "enum", "hg/inc/hui.h:HAP_POP_MIXED", sep=""), + v("hapmapSnps_monomorphic_", "bool", + "hg/inc/hui.h:HAP_MONO_PREFIX", sep=""), + v("hapmapSnps_ortho_", "bool", + "hg/inc/hui.h:HAP_ORTHO_PREFIX", sep=""), + v("hapmapSnps_orthoQual_", "int", + "hg/inc/hui.h:HAP_ORTHO_QUAL_PREFIX", sep=""), + v("exprssn.color", "enum", "hg/hgTrackUi/hgTrackUi.c:1287", sep="", + values=["rg", "rb"], + note="Shared by affy, affyAllExon and rosetta: one namespace, three " + "tracks."), + v("hgt.affyPhase2.tnfg", "enum", "hg/hgTrackUi/hgTrackUi.c:2409", sep="", + note="affyTxnPhase2 track, parked in the hgt.* namespace."), + v("snp125ColorSource and the snp125*OldColorVars arrays", "string", + "hg/cgilib/snp125Ui.c:snp125OldColorVarToNew", sep="", + note="Pre-. spellings, still read for backward compatibility " + "and rewritten to the track-scoped form."), +] + +# --------------------------------------------------------------------------- +# Other CGIs that keep per-track state in the same cart. hgTracks and +# hgTrackUi are not the only writers, so an accessor layer that lives in +# hg/lib has to cover these too. +# --------------------------------------------------------------------------- + +OTHER_CGIS = { + "hgc": { + "what": "The details page reads most of the same vars hgTracks does, " + "but it also owns a few of its own, and in two places it " + "spells a shared var differently.", + "vars": [ + v("speciesOrder", "string", "hg/hgc/mafClick.c:609", + note="maf and rnaFold details pages; user-chosen species " + "order."), + v("vis", "enum", "hg/hgc/mafClick.c:584", + note="Per-species visibility on the maf details page."), + v("_pairEndsByName", "bool", "hg/hgc/bamClick.c:271", sep="_", + note="INCONSISTENCY: hui.c writes this as " + ".pairEndsByName (dot), hgc reads it with an " + "underscore, so the details page does not follow the UI " + "setting. Worth reconciling before either form is baked " + "into a schema."), + v("_geneTrack", "list", "hg/hgc/hgc.c:19635", sep="_", + multi=True, + note="snp125-era gene tracks for functional annotation, " + "written by hgTrackUi.c:191. Not to be confused with the " + "bigDbSnp .geneTrack: separate features, each " + "internally consistent."), + v("interProXref", "bool", "hg/hgc/lowelab.c:753", + note="Lowe lab tracks."), + ], + }, + "hgc extended DNA": { + "what": "The Extended DNA page (hg/hgc/hgc.c:doGetDnaExtended1) keeps " + "one case/color set per track. A real per-track group that " + "no cfgUi function knows about.", + "vars": [ + v("_case", "bool", "hg/hgc/hgc.c:5746", sep="_", + note="Upper case this track's bases."), + v("_u", "bool", "hg/hgc/hgc.c:5748", sep="_", note="Underline."), + v("_b", "bool", "hg/hgc/hgc.c:5750", sep="_", note="Bold."), + v("_i", "bool", "hg/hgc/hgc.c:5752", sep="_", note="Italic."), + v("_red", "int", "hg/hgc/hgc.c:5754", sep="_", note="0-255."), + v("_green", "int", "hg/hgc/hgc.c:5756", sep="_", note="0-255."), + v("_blue", "int", "hg/hgc/hgc.c:5758", sep="_", note="0-255."), + ], + }, + "hgTables": { + "what": "hgTables addresses the SAME data by db and table rather than " + "by track, so its per-dataset state does not live under the " + "track name at all. This is the biggest structural mismatch " + "in the cart: two CGIs, two namespaces, one dataset.", + "vars": [ + v("hgta_fil.v....pat", "string", + "hg/hgTables/filterFields.c:646", sep="", + note="Filter text box. Sibling types are .dd (dropdown), " + ".cmp (comparison), .rawQuery, .maxOutput."), + v("hgta_fs.check..
.", "bool", + "hg/hgTables/filterFields.c:251", sep="", + note="Output field selection."), + v("hgta_subtrackMerge*", "string", + "hg/hgTables/hgTables.h:534", sep="", + note="Primary, Op, MoreThreshold, LessThreshold, WigOp, " + "RequireAll, UseMinScore, MinScore."), + v("_sel", "bool", "hg/hgTables/compositeTrack.c:67", sep="_", + note="The one place hgTables does use the track-scoped form: " + "it reads subtrack selection the same way hgTracks does."), + v("hgta_track, hgta_table, hgta_database", "string", + "hg/hgTables/hgTables.h:467", sep="", + note="Current selection, session-scoped rather than " + "per-track."), + ], + }, +} + +# --------------------------------------------------------------------------- +# Track-scoped state that does NOT start with the track name. These are the +# cases a " at the top" hierarchy has to special-case. +# --------------------------------------------------------------------------- + +EXCEPTIONS = [ + {"pattern": "cgs__", + "what": "chromGraph settings", + "src": "hg/lib/chromGraph.c:chromGraphVarName", + "why": "Prefix comes first, so a prefix scan for '.' misses it."}, + {"pattern": "hgtgroup__close", + "what": "Track group open/closed on the main page", + "src": "hg/hgTrackUi/hgTrackUi.c:3917", + "why": "Keyed by track group, not by track."}, + {"pattern": "hapmapSnps_monomorphic_, hapmapSnps_ortho_, " + "hapmapSnps_orthoQual_", + "what": "HapMap SNP filters", + "src": "hg/hgTrackUi/hgTrackUi.c:2608", + "why": "Shared across the whole hapmapSnps track set, keyed by " + "population/species rather than by track."}, + {"pattern": "complement_, hgt.baseTitle_", + "what": "Base Position ruler options", + "src": "hg/hgTrackUi/hgTrackUi.c:2155", + "why": "Assembly-scoped, not track-scoped, even though they are edited " + "from the ruler's config page."}, + {"pattern": "dup_tracks", + "what": "List of duplicated tracks", + "src": "hg/inc/dupTrack.h:DUP_TRACKS_VAR", + "why": "Points at a trash file that defines the dup__ " + "namespaces."}, + {"pattern": ".sha1, multiRegionBedPadding, virtWinFull", + "what": "Multi-region state", + "src": "hg/inc/hui.h:176", + "why": "Mixed: the sha1 is track-scoped but the rest is session-scoped."}, + {"pattern": "hgt.oligoMatch, hgt.cutters, hgt.gcOnFly, hgt.motifs", + "what": "Settings for the synthetic tracks (Short Match, Restriction " + "Enzymes, GC on the fly, ruler motifs)", + "src": "hg/inc/hui.h:83-127", + "why": "These tracks store their state in the hgt.* CGI namespace " + "rather than under their own track name."}, + {"pattern": "_facet_*, _order, _page", + "what": "Faceted table and sortable table state", + "src": "hg/lib/facetedTable.c, hg/lib/tablesTables.c", + "why": "varPrefix is usually but not always the track name."}, + {"pattern": "hgt__filterType, hgt__filterPmId", + "what": "Database of Genomic Variants filters", + "src": "hg/hgTrackUi/hgTrackUi.c:dgvUi", + "why": "Track name sits in the middle of the name, so neither a " + "'.' prefix scan nor a suffix scan finds it."}, + {"pattern": "..", + "what": "A composite view", + "src": "hg/lib/cart.c:cartLookUpVariableClosestToHome", + "why": "Not really an exception, but worth stating: the middle " + "component is a view name, so a two-component parse of " + "'.' is wrong for composites."}, +] + +# --------------------------------------------------------------------------- +# assemble +# --------------------------------------------------------------------------- + +def build(): + return { + "ticket": 37838, + "what": "Track-scoped cart variables, arranged as the hierarchy a " + "JSON cart and a cart accessor layer would use.", + "naming": NAMING, + "levels": { + "1_trackName": { + "what": "Top of the hierarchy. Every variable below is " + "scoped by one track name (or by a composite/view " + "above that track).", + "prefixes": NAMING["trackNamePrefixes"], + }, + "2_common": { + "what": "Applies to a track of any type.", + "groups": COMMON, + }, + "2b_container": { + "what": "Applies to a track that contains other tracks.", + "groups": CONTAINER, + }, + "3_byType": { + "what": "Keyed by eCfgType (hg/inc/trackDb.h:439) where one " + "exists, otherwise by the type or track-name special " + "case that supplies the UI.", + "types": TYPES, + }, + "3b_byTrackName": { + "what": "Tracks whose vars are hard-coded literals rather " + "than composed from tdb->track. Same . " + "shape, but invisible to a search for the suffix.", + "tracks": BY_TRACK_NAME, + }, + "4_families": { + "what": "Leaf groups shared by several types. A type " + "references these instead of repeating them; several " + "are themselves keyed by field or by name, which is " + "where the hierarchy goes one level deeper.", + "groups": FAMILIES, + }, + }, + "otherCgis": { + "what": "CGIs other than hgTracks/hgTrackUi that keep per-track " + "or per-dataset state in the same cart.", + "groups": OTHER_CGIS, + }, + "notScopedByTrackName": { + "what": "Configures one track, but the name has no track " + "component, so an accessor keyed on tdb->track cannot " + "reach it.", + "vars": GLOBAL_BUT_TRACK_SPECIFIC, + }, + "exceptions": EXCEPTIONS, + } + + +def counts(cat): + n_common = sum(len(g["vars"]) for g in COMMON.values()) + n_cont = sum(len(g["vars"]) for g in CONTAINER.values()) + n_fam = sum(len(g["vars"]) for g in FAMILIES.values()) + n_type = sum(len(t["vars"]) for t in TYPES.values()) + n_name = sum(len(t["vars"]) for t in BY_TRACK_NAME.values()) + n_glob = len(GLOBAL_BUT_TRACK_SPECIFIC) + n_cgi = sum(len(g["vars"]) for g in OTHER_CGIS.values()) + return { + "common": n_common, + "container": n_cont, + "families": n_fam, + "types": n_type, + "byTrackName": n_name, + "notScopedByTrack": n_glob, + "otherCgis": n_cgi, + "typeCount": len(TYPES), + "total": (n_common + n_cont + n_fam + n_type + n_name + n_glob + + n_cgi), + } + + +# --------------------------------------------------------------------------- +# HTML rendering +# --------------------------------------------------------------------------- + +CSS = """ +body { font: 14px/1.5 -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; + margin: 0; color: #12191f; background: #fff; } +header { background: #14385c; color: #fff; padding: 18px 28px; } +header h1 { margin: 0 0 4px; font-size: 20px; font-weight: 600; } +header p { margin: 0; font-size: 13px; color: #c5d6e8; } +main { max-width: 1080px; margin: 0 auto; padding: 22px 28px 60px; } +h2 { font-size: 17px; margin: 30px 0 6px; padding-bottom: 5px; + border-bottom: 2px solid #14385c; } +h3 { font-size: 15px; margin: 20px 0 4px; color: #14385c; } +p.what { margin: 4px 0 10px; color: #4a5764; font-size: 13px; + max-width: 78ch; } +table { border-collapse: collapse; width: 100%; margin: 6px 0 14px; + font-size: 13px; } +th { text-align: left; background: #eef2f6; padding: 5px 8px; + border-bottom: 1px solid #c9d3dd; font-weight: 600; } +td { padding: 5px 8px; border-bottom: 1px solid #eceff2; + vertical-align: top; } +tr:hover td { background: #f7fafd; } +code, .n { font-family: ui-monospace, Menlo, Consolas, monospace; + font-size: 12.5px; } +.n { font-weight: 600; color: #0b3d62; white-space: nowrap; } +.t { color: #7a3ba8; white-space: nowrap; } +.src { color: #6b7885; font-size: 11.5px; white-space: nowrap; } +.note { color: #4a5764; font-size: 12.5px; } +.vals { color: #276749; font-size: 12px; } +.legacy { background: #fff8e1; } +.pill { display: inline-block; background: #e8eef5; color: #14385c; + border-radius: 9px; padding: 1px 8px; font-size: 11.5px; + margin-right: 5px; } +.tree { font-family: ui-monospace, Menlo, Consolas, monospace; + font-size: 12.5px; background: #f7fafd; border: 1px solid #dde5ec; + padding: 12px 14px; white-space: pre; overflow-x: auto; } +#filter { width: 320px; padding: 6px 9px; font-size: 13px; + border: 1px solid #b9c4cf; border-radius: 4px; margin: 10px 0; } +.hidden { display: none; } +.count { color: #6b7885; font-weight: 400; font-size: 13px; } +""" + +TREE = """ visibility (bare name) + | + +- common to any track ................. _sel _imgOrd _hideKids + | priority group heightPer + | colorOverride[On] + | nameFilter doWiggle doMergeItems + | section_
_close + | + +- container layer ..................... composite: displaySubtracks, + | hideEmptySubtracks, sortOrder, + | filterComp. + | view: . + | multiWig: aggregate, viewFunc + | + +- type layer (eCfgType) ............... wig | bedScore | bedFilt | peak | + | genePred | psl | chain | net | + | wigMaf | bam | vcf | snake | long | + | interact | hic | barChart | lolly | + | bigDbSnp | bigRmsk (+ non-eCfgType: + | gtex, expRatio, sample, chromGraph, + | factorSource, ld, gvf, snp125, + | blast, pubs, transMap, mrna) + | + +- by track name (literal vars) ........ stsMap.filter cghNci60.color + | switchDbTss.pseudo rosetta.et ... + | + +- leaf groups (shared, and nested) .... filter.[Min|Max] + filterBy. (list) + filterText. + filterType. + highlight*. (twins) + cds: baseColorDrawOpt, codonNumbering + label: label, label. + decorator.. <- nested + (wigMaf) + (snp125 color) + +other writers of the same cart: + hgc ................................... .speciesOrder .vis + _case/_u/_b/_i/_red/_green/_blue + hgTables .............................. hgta_fil.v..
.. + hgta_fs.check..
. + (addresses data by db.table, NOT by + track - the big mismatch) +""" + + +def esc(s): + return html.escape(str(s), quote=False) + + +def var_rows(vars_, prefix=None): + """prefix replaces the generic stand-in, for the by-track-name + section where the real track name is part of the literal var name.""" + stand_in = esc(prefix) if prefix else "<track>" + out = [] + for e in vars_: + sep = e.get("sep", ".") + name = e["name"] + if sep == "": + # empty name = the bare track name (visibility); otherwise the + # var has an absolute name with no track component at all + full = stand_in if not name else esc(name) + elif sep in (".", "_"): + # legacy entries already carry their leading underscore + joiner = "" if name.startswith(sep) else sep + full = stand_in + esc(joiner) + esc(name) + else: + full = esc(sep) + esc(name) + cls = ' class="legacy"' if sep == "_" else "" + bits = [] + if e.get("multi"): + bits.append('multi') + if e.get("values"): + bits.append('' + + esc(" | ".join(e["values"])) + "") + if e.get("default") is not None: + bits.append('default ' + + esc(e["default"]) + "") + if e.get("tdbDefault"): + bits.append('trackDb: ' + + esc(e["tdbDefault"]) + "") + if e.get("note"): + bits.append('' + esc(e["note"]) + "") + out.append( + "" + "" + % (cls, full, esc(e["type"]), " ".join(bits), esc(e["src"]))) + return "\n".join(out) + + +def table(vars_, prefix=None): + if not vars_: + return "

No vars of its own; see the leaf groups it "\ + "pulls in.

" + return ("
%s%s%s%s
" + "%s
variabletypevalues / notesread at
" % var_rows(vars_, prefix)) + + +def render_html(cat): + c = counts(cat) + p = [] + p.append("Track cart variables (#37838)") + p.append("" % CSS) + p.append("

Track-scoped cart variables

" + "

Refs #37838 — arranged as the hierarchy a JSON cart " + "and a cart accessor layer would use. %d variables across %d " + "track types.

" % (c["total"], c["typeCount"])) + p.append("
") + + p.append("

The shape

") + p.append("
%s
" % esc(TREE)) + + p.append("

How a name is built

") + n = cat["naming"] + p.append("

Canonical form %s. Legacy form " + "%s (highlighted in yellow below). %s

" + % (esc(n["canonical"]), esc(n["legacy"]), esc(n["legacyNote"]))) + p.append("

Lookup order (%s): %s. %s

" + % (esc(n["lookupOrderSrc"]), + " → ".join("%s" % esc(x) + for x in n["lookupOrder"]), + esc(n["lookupOrderNote"]))) + p.append("

Values. %s

" + % esc(n["valueEncoding"])) + p.append("

Track name prefixes. %s

" + % ", ".join("%s (%s)" % (esc(x["prefix"]), + esc(x["what"])) + for x in n["trackNamePrefixes"])) + + p.append("") + + p.append("

Level 2 — common to any track " + "(%d)

" % c["common"]) + for k, g in COMMON.items(): + p.append("

%s

%s

%s" + % (esc(k), esc(g["what"]), table(g["vars"]))) + + p.append("

Level 2b — containers " + "(%d)

" % c["container"]) + for k, g in CONTAINER.items(): + p.append("

%s

%s

%s" + % (esc(k), esc(g["what"]), table(g["vars"]))) + + p.append("

Level 3 — by track type " + "(%d in %d types)

" + % (c["types"], c["typeCount"])) + for k, t in TYPES.items(): + p.append("

%s

" % esc(k)) + meta = ["%s" % esc(t["cfgType"])] + meta.append("tdb type: %s" + % esc(", ".join(t["tdbTypes"]))) + p.append("

%s
%s%s

" + % (" ".join(meta), esc(t["cfgUi"]), + ("
%s" % esc(t["note"])) + if t.get("note") else "")) + if t.get("families"): + p.append("

Also uses: %s

" + % ", ".join("%s" % esc(f) + for f in t["families"])) + p.append(table(t["vars"])) + if t.get("tdbOnly"): + p.append("

trackDb only (no cart var, but " + "supplies defaults): %s

" + % ", ".join("%s" % esc(x) + for x in t["tdbOnly"])) + + p.append("

Level 3b — by track name " + "(%d)

" % c["byTrackName"]) + p.append("

These write their variables as literals " + "(\"stsMap.filter\") instead of composing them from " + "tdb->track. Same shape, but a suffix search " + "will not find them, which is why they are easy to miss in a " + "rewrite.

") + for k, t in BY_TRACK_NAME.items(): + p.append("

%s

%s%s

" + % (esc(k), esc(t["cfgUi"]), + ("
%s" % esc(t["note"])) + if t.get("note") else "")) + # use the real track name in the rendered var when the key is a + # single track rather than a group of them + pfx = k if re.fullmatch(r"[A-Za-z0-9_]+", k) else None + p.append(table(t["vars"], pfx)) + + p.append("

Not scoped by track name " + "(%d)

" % c["notScopedByTrack"]) + p.append("

Each of these configures exactly one track (or " + "one small family of tracks) but carries no track component in " + "its name, so an accessor keyed on tdb->track " + "cannot reach it and a JSON cart cannot file it under the " + "track. They need either a rename or an explicit alias " + "table.

") + p.append(table(GLOBAL_BUT_TRACK_SPECIFIC)) + + p.append("

Level 4 — shared leaf groups " + "(%d)

" % c["families"]) + for k, g in FAMILIES.items(): + p.append("

%s

%s

%s" + % (esc(k), esc(g["what"]), table(g["vars"]))) + + p.append("

Other CGIs " + "(%d)

" % c["otherCgis"]) + p.append("

hgTracks and hgTrackUi are not the only writers " + "of per-track cart state, so an accessor layer in hg/lib has to " + "account for these as well.

") + for k, g in OTHER_CGIS.items(): + p.append("

%s

%s

%s" + % (esc(k), esc(g["what"]), table(g["vars"]))) + + p.append("

Exceptions — track state not under the track name

") + p.append("

These are the cases that break a strict " + "<track>.<var> hierarchy, so any " + "accessor layer or JSON schema has to handle them " + "deliberately.

") + p.append("") + for e in EXCEPTIONS: + p.append("" + "" + % (esc(e["pattern"]), esc(e["what"]), esc(e["why"]), + esc(e["src"]))) + p.append("
patternwhatwhy it is " + "awkwardsrc
%s%s%s%s
") + + p.append("
") + p.append("""""") + return "\n".join(p) + + +def main(): + ap = argparse.ArgumentParser(description=__doc__) + ap.add_argument("--json") + ap.add_argument("--html") + ap.add_argument("--check", action="store_true") + args = ap.parse_args() + cat = build() + if args.json: + with open(args.json, "w") as f: + json.dump(cat, f, indent=1) + print("wrote %s" % args.json) + if args.html: + with open(args.html, "w") as f: + f.write(render_html(cat)) + print("wrote %s" % args.html) + if args.check or not (args.json or args.html): + c = counts(cat) + for k in sorted(c): + print("%-12s %s" % (k, c[k])) + # every family referenced by a type must exist + bad = 0 + for name, t in TYPES.items(): + for fam in t.get("families", []): + key = fam.split(" ")[0] + if key not in FAMILIES and key not in TYPES: + print("unknown family %r referenced by type %r" + % (fam, name), file=sys.stderr) + bad += 1 + if bad: + return 1 + print("families ok") + return 0 + + +if __name__ == "__main__": + sys.exit(main())