350733c85caaaebfe5c82892e57a38d60e70c1c3
max
  Mon Jul 20 11:23:01 2020 -0700
fixing a previous commit that I had reverted, refs #25887. Code review note: ignore the original commit and its reverted cousin
This is the only relevant commit.

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 7d44b40..7fe281e 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -2132,56 +2132,84 @@
 }
 
 struct highlightVar
 // store highlight information
 {
 struct highlightVar *next;
 char *db;
 char *chrom;
 long chromStart;
 long chromEnd;
 char *hexColor;
 };
 
 struct highlightVar *parseHighlightInfo()
 // Parse highlight info from cart var to a linked list of highlightVar structs
-// db.chrom:start-end#hexColor|db.chrom:start-end#hexColor|...
+// Accepts three input formats for the highlight variable:
+// 1) db.chrom:start-end (format in very old carts)
+// 2) db.chrom:start-end#hexColor|db.chrom:start-end#hexColor|... (old format)
+// 3) db#chrom#start#end#hexColor|db#chrom#start#end#hexColor|... (current format, to allow . in seq names)
+//
 {
 struct highlightVar *hlList = NULL;
 char *highlightDef = cartOptionalString(cart, "highlight");
 if(highlightDef)
     {
     char *hlArr[256];
     int hlCount = chopByChar(cloneString(highlightDef), '|', hlArr, ArraySize(hlArr));
     int i;
     for (i=0; i<hlCount; i++)
         {
         char *oneHl = hlArr[i];
         struct highlightVar *h;
+        char *chromStart, *chromEnd;
         AllocVar(h);
+        if (countSeparatedItems(oneHl, '#')==5)
+            // the new format: db#chrom#start#end#color
+            {
+            h->db     = cloneNextWordByDelimiter(&oneHl,'#');
+            h->chrom  = cloneNextWordByDelimiter(&oneHl,'#');
+            chromStart = cloneNextWordByDelimiter(&oneHl,'#');
+            chromEnd = cloneNextWordByDelimiter(&oneHl,'#');
+            h->hexColor = cloneString(oneHl);
+            }
+        else  // the syntax only used in old saved sessions
+            // the old format: db.chr:start-end followed optionally by #color
+            {
             h->db     = cloneNextWordByDelimiter(&oneHl,'.');
             h->chrom  = cloneNextWordByDelimiter(&oneHl,':');
+            chromStart = cloneNextWordByDelimiter(&oneHl,'-');
+            chromEnd = cloneNextWordByDelimiter(&oneHl,'#');
+            if (oneHl && *oneHl != '\0')
+                h->hexColor = cloneString(oneHl);
+            }
+
+        if (!isEmpty(chromStart) && !isEmpty(chromEnd) &&
+                isNumericString(chromStart) && isNumericString(chromEnd) &&
+                !isEmpty(h->db) && !isEmpty(h->chrom))
+            {
             // long to handle virt chrom coordinates
-        h->chromStart = atol(cloneNextWordByDelimiter(&oneHl,'-'));
-        h->chromEnd   = atol(cloneNextWordByDelimiter(&oneHl,'#'));
+            h->chromStart = atol(chromStart);
+            h->chromEnd   = atol(chromEnd);
             h->chromStart--; // Not zero based
-        if (highlightDef && *highlightDef != '\0')
-            h->hexColor = cloneString(oneHl);
             slAddHead(&hlList, h);
             }
+        }
+
     slReverse(&hlList);
     }
+
 return hlList;
 }
 
 static void highlightRegions(struct cart *cart, struct hvGfx *hvg, int imagePixelHeight)
 // Highlights regions in the image.  Only done if theImgBox is not defined.
 // Thus it is done for ps/pdf and view image but the hgTracks image is highlighted via js
 {
 struct highlightVar *hlList = parseHighlightInfo();
 
 if(hlList && theImgBox == NULL) // Only highlight region when imgBox is not used. (pdf and show-image)
     {
     struct highlightVar *h;
     for (h=hlList; h; h=h->next)
         {
         if (virtualSingleChrom()) // DISGUISE VMODE
@@ -9135,31 +9163,31 @@
 }
 
 void remapHighlightPos()
 // Remap non-virt highlight position if any to new virtMode chrom.
 {
 if (virtualSingleChrom())
     return;
 struct highlightVar *h = parseHighlightInfo();
 if (h && h->db && sameString(h->db, database))
     {
     long virtStart = 0, virtEnd = 0;
     if (findNearestVirtMatch(h->chrom, h->chromStart, h->chromEnd, FALSE, &virtStart, &virtEnd)) // try to find the nearest match
 	{
 	// save new highlight position to cart var
 	char cartVar[1024];
-	safef(cartVar, sizeof cartVar, "%s#%s#%ld#%ld#%s", h->db, "virt", virtStart, virtEnd, h->hexColor);
+	safef(cartVar, sizeof cartVar, "%s.%s:%ld-%ld#%s", h->db, "virt", virtStart, virtEnd, h->hexColor);
 	cartSetString(cart, "highlight", cartVar);
 	}
     else
 	{
 	// erase the highlight cartvar if it has no overlap with the new virt chrom
 	cartRemove(cart, "highlight");
 	}
     }
 }
 
 
 void tracksDisplay()
 /* Put up main tracks display. This routine handles zooming and
  * scrolling. */
 {