83858083785a6b2b1f3c05f93e818e5a89318692 max Tue Aug 25 01:42:34 2026 -0700 hgSession: show cytoBand and gene/locus annotations for each saved session; date-only Created/Last used columns with full timestamp on hover. Factor locusName lookup into reusable hLocusName/hLocusNameExpand in hdb.c and reuse from hgBlat. refs #38157 The Assembly column now shows band, gene/locus name and Mbp position (separated by whitespace, normal text size). hLocusNameExpand centralizes the ex:/in:/ig: and | to - expansion that hgBlat's results page did inline. diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c index 910a3a8922b..61c17b9f7ce 100644 --- src/hg/lib/hdb.c +++ src/hg/lib/hdb.c @@ -1429,30 +1429,70 @@ boolean hChromBand(char *db, char *chrom, int pos, char retBand[HDB_MAX_BAND_STRING]) /* Return text string that says what band pos is on. * Return FALSE if not on any band, or table missing. */ { if (trackHubDatabase(db) || !hTableExists(db, "cytoBand")) return FALSE; else { struct sqlConnection *conn = hAllocConn(db); boolean ok = hChromBandConn(conn, chrom, pos, retBand); hFreeConn(&conn); return ok; } } +char *hLocusNameExpand(char *raw) +/* Expand the abbreviations in a locusName-table label into a human-readable string: + * "ex:" -> "exon ", "in:" -> "intron ", "ig:" -> "intergenic ", and the "|" that + * separates gene symbols -> "-". Returns a cloneString'd value (caller frees), or + * NULL for empty input. */ +{ +if (isEmpty(raw)) + return NULL; +struct dyString *dy = dyStringNew(64); +char *genes = raw; +if (startsWith("ex:", raw)) + { dyStringAppend(dy, "exon "); genes = raw + 3; } +else if (startsWith("in:", raw)) + { dyStringAppend(dy, "intron "); genes = raw + 3; } +else if (startsWith("ig:", raw)) + { dyStringAppend(dy, "intergenic "); genes = raw + 3; } +char *dupe = cloneString(genes); +subChar(dupe, '|', '-'); +dyStringAppend(dy, dupe); +freeMem(dupe); +return dyStringCannibalize(&dy); +} + +char *hLocusName(struct sqlConnection *conn, char *chrom, int start, int end) +/* If conn's database has a "locusName" table, look up the gene/locus label that overlaps + * the given range and return it expanded into a human-readable string ("intron STON2", + * "intergenic FOO-BAR"), or NULL if the table is absent or nothing overlaps. Caller frees. + * Reused by hgBlat (result labels) and hgSession (saved-session region column). */ +{ +if (!sqlTableExists(conn, "locusName")) + return NULL; +struct sqlResult *sr = hRangeQuery(conn, "locusName", chrom, start, end, NULL, 0); +char **row = sqlNextRow(sr); +char *label = NULL; +if (row != NULL) + label = hLocusNameExpand(row[4]); +sqlFreeResult(&sr); +return label; +} + boolean hScaffoldPos(char *db, char *chrom, int start, int end, char **retScaffold, int *retStart, int *retEnd) /* Return the scaffold, and start end coordinates on a scaffold, for * a chromosome range. If the range extends past end of a scaffold, * it is truncated to the scaffold end. * Return FALSE if unable to convert */ { int ret = FALSE; char table[HDB_MAX_TABLE_STRING]; safef(table, sizeof(table), "%s_gold", chrom); if (!hTableExists(db, table)) return FALSE; else { char query[256];