39209bcbf0111b14b2b8aca1bb8fc245079a7226
max
  Mon Jun 30 06:22:32 2025 -0700
show locus name on blat results table, refs #35993

diff --git src/hg/hgBlat/hgBlat.c src/hg/hgBlat/hgBlat.c
index 120b1b9bbb7..bfdeb159b6e 100644
--- src/hg/hgBlat/hgBlat.c
+++ src/hg/hgBlat/hgBlat.c
@@ -22,30 +22,31 @@
 #include "blatServers.h"
 #include "web.h"
 #include "hash.h"
 #include "botDelay.h"
 #include "trashDir.h"
 #include "trackHub.h"
 #include "hgConfig.h"
 #include "errCatch.h"
 #include "portable.h"
 #include "portable.h"
 #include "dystring.h"
 #include "chromInfo.h"
 #include "net.h"
 #include "fuzzyFind.h"
 #include "chromAlias.h"
+#include "subText.h"
 
 struct cart *cart;	/* The user's ui state. */
 struct hash *oldVars = NULL;
 boolean orgChange = FALSE;
 boolean dbChange = FALSE;
 boolean allGenomes = FALSE;
 boolean allResults = FALSE;
 static long enteredMainTime = 0;
 
 
 boolean autoBigPsl = FALSE;  // DEFAULT VALUE change to TRUE in future
 
 /* for earlyBotCheck() function at the beginning of main() */
 #define delayFraction   0.5    /* standard penalty is 1.0 for most CGIs */
                                 /* this one is 0.5 */
@@ -827,56 +828,80 @@
 
         printf("<TR><TD> Custom track description: ");
         cgiMakeTextVar( "trackDescription", trackDescription,50);
         printf("</TD></TR>");
         printf("<TR><TD><INPUT TYPE=SUBMIT NAME=Submit VALUE=\"Create a stable custom track with these results\">\n");
         printInfoIcon("The BLAT results below are temporary and will be replaced by your next BLAT search. "
                 "However, when saved as a custom track with the button on the left, BLAT results are stored on our "
                 "servers and can be saved as stable session (View &gt; My Sessions) links that can be shared via email or in manuscripts. "
                 "\n<p>We have never cleaned up the data under stable session links so far. "
                 "To reduce track clutter in your own sessions, you can delete BLAT custom tracks from the main Genome Browser "
                 "view using the little trash icon next to each custom track.</p>");
         puts("</TD></TR>");
         printf("</TABLE></FORM></DIV>");
         }
 
+        boolean hasDb = sqlDatabaseExists(database);
+        struct sqlConnection *locusConn = NULL;
+        struct subText *subList = NULL;
+        if (hasDb)
+            {
+	    struct sqlConnection *conn = hAllocConn(database);
+            if (cfgOptionBooleanDefault("blatShowLocus", FALSE) && sqlTableExists(conn, "locusName") )
+                {
+                locusConn = hAllocConn(database);
+                slSafeAddHead(&subList, subTextNew("ig:", "intergenic "));
+                slSafeAddHead(&subList, subTextNew("ex:", "exon "));
+                slSafeAddHead(&subList, subTextNew("in:", "intron "));
+                slSafeAddHead(&subList, subTextNew("|", "-"));
+                }
+            hFreeConn(&conn);
+            }
+
     printf("<DIV STYLE=\"display:block;\"><PRE>");
 
     // find maximum query name size for padding calculations and
     // find maximum target chrom name size for padding calculations
     int maxQChromNameSize = 0;
     int maxTChromNameSize = 0;
     for (psl = pslList; psl != NULL; psl = psl->next)
 	{
 	int qLen = strlen(psl->qName);
 	maxQChromNameSize = max(maxQChromNameSize,qLen);
 	int tLen = strlen(psl->tName);
 	maxTChromNameSize = max(maxTChromNameSize,tLen);
 	}
     maxQChromNameSize = max(maxQChromNameSize,5);
     maxTChromNameSize = max(maxTChromNameSize,5);
 
-    printf("   ACTIONS                 QUERY ");
+    printf("   ACTIONS ");
+    if (locusConn)
+        // 25 characters wide
+        printf("               LOCUS ");
+
+    printf("                 QUERY ");
     
     spaceOut(stdout, maxQChromNameSize - 5);
 
     printf("SCORE START   END QSIZE IDENTITY  CHROM ");
     spaceOut(stdout, maxTChromNameSize - 5);
 
     printf(" STRAND  START       END   SPAN\n");
 
     printf("----------------------------------------------------------------------------------------------------------");
+    if (locusConn)
+        repeatCharOut(stdout, '-', 25);
     repeatCharOut(stdout, '-', maxQChromNameSize - 5);
     repeatCharOut(stdout, '-', maxTChromNameSize - 5);
 
     printf("\n");
 
     for (psl = pslList; psl != NULL; psl = psl->next)
 	{
         char *browserHelp = "Open a Genome Browser showing this match";
         char *helpText = "Open a Genome Browser with the BLAT results, but in a new internet browser tab";
         // XX putting SVG into C code like this is ugly. define somewhere? maybe have globals for these?
         char *icon = "<svg style='height:10px; padding-left:2px' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d='M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32h82.7L201.4 265.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3V192c0 17.7 14.3 32 32 32s32-14.3 32-32V32c0-17.7-14.3-32-32-32H320zM80 32C35.8 32 0 67.8 0 112V432c0 44.2 35.8 80 80 80H400c44.2 0 80-35.8 80-80V320c0-17.7-14.3-32-32-32s-32 14.3-32 32V432c0 8.8-7.2 16-16 16H80c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16H192c17.7 0 32-14.3 32-32s-14.3-32-32-32H80z'/></svg>";
 
 
 	if (customText)
 	    {
@@ -903,30 +928,46 @@
 		{
 		printf("<A TITLE='%s' HREF=\"%s?position=%s:%d-%d&db=%s&ss=%s+%s&%s%s\">browser</A>&nbsp;",
 		    browserHelp, browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database, 
 		    pslName, faName, uiState, unhideTrack);
 		printf("<A TITLE='%s' TARGET=_BLANK HREF=\"%s?position=%s:%d-%d&db=%s&ss=%s+%s&%s\">new tab%s</A>&nbsp;",
 		    helpText, browserUrl, psl->tName, psl->tStart + 1, psl->tEnd, database, 
 		    pslName, faName, unhideTrack, icon);
 		}
 	    }
 	printf("<A title='Show query sequence, genome hit and sequence alignment' "
                 "HREF=\"%s?o=%d&g=htcUserAli&i=%s+%s+%s&c=%s&l=%d&r=%d&db=%s&%s\">", 
 	    hgcUrl, psl->tStart, pslName, cgiEncode(faName), psl->qName,  psl->tName,
 	    psl->tStart, psl->tEnd, database, uiState);
 	printf("details</A> ");
 
+        // print name of this locus
+        if (locusConn)
+            {
+            struct sqlResult *sr = hRangeQuery(locusConn, "locusName", psl->tName, psl->tStart, psl->tEnd, NULL, 0);
+            char **row;
+            row = sqlNextRow(sr);
+            if (row != NULL)
+                {
+                char *desc = row[4];
+                char *descLong = subTextString(subList, desc);
+                printf("%-25s", descLong);
+                freeMem(descLong);
+                }
+            sqlFreeResult(&sr);
+            }
+
 	printf("%s",psl->qName);
 	spaceOut(stdout, maxQChromNameSize - strlen(psl->qName));
 	printf(" %5d %5d %5d %5d   %5.1f%%  ",
 	    pslScore(psl), psl->qStart+1, psl->qEnd, psl->qSize,
 	    100.0 - pslCalcMilliBad(psl, TRUE) * 0.1);
         char *displayChromName = chromAliasGetDisplayChrom(database, cart, psl->tName);
 	printf("%s",displayChromName);
 	spaceOut(stdout, maxTChromNameSize - strlen(displayChromName));
 	printf("  %-2s  %9d %9d %6d",
 	    psl->strand, psl->tStart+1, psl->tEnd,
 	    psl->tEnd - psl->tStart);
 
         // if you modify this, also modify hgPcr.c:doQuery, which implements a similar feature
         char *seq = psl->tName;
         if (endsWith(seq, "_fix"))