994528edb7d89068f371fef6d8a5fc72566f7334
lrnassar
  Fri Sep 4 13:35:16 2026 -0700
Adding an opt-in "Keep only last search" checkbox to the new BLAT search form. refs #36292

Behind a new hg.conf setting, blatOnlyLatestCheckbox (default off, documented in ex.hg.conf).
When checked, each new BLAT search removes the user's earlier BLAT result tracks in hgc's
buildBigPsl (cart variable blatOnlyLatest, remembered per browser in localStorage); unchecked
keeps the current accumulate behavior, so site defaults are unchanged. Deletion requires both
the hg.conf setting and the cart variable, so a stale cart cannot delete tracks where the
feature is off. Independent of, and coexists with, the blatOldTracks hg.conf setting.

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 017daa1bb4e..0afd5b635ff 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -27593,30 +27593,53 @@
             {
             if (sameString(oldTracks, "hide"))
                 {
                 cartSetString(cart, ct->tdb->track, "hide");
                 slAddHead(&keptList, ct);   /* keep it in the session, just hidden */
                 }
             /* "delete": drop it from the list so customTracksSaveCart writes it out */
             }
         else
             slAddHead(&keptList, ct);
         }
     slReverse(&keptList);
     ctList = keptList;
     }
 
+/* "Keep only last search" (RM #38086): per-user opt-in to remove earlier BLAT result tracks,
+ * the checkbox inverse of blatOldTracks=delete above (left untouched).  With the box unchecked
+ * (the default) results accumulate exactly as before, so removal only ever happens because the
+ * user asked for it.  Gated on the same hg.conf setting that shows the checkbox, so a stale
+ * cart variable cannot delete tracks on a site where the feature is off. */
+if (sameString(cfgOptionDefault("blatOnlyLatestCheckbox", "off"), "on")
+    && cartUsualBoolean(cart, "blatOnlyLatest", FALSE))
+    {
+    struct customTrack *ct, *next, *keptList = NULL;
+    for (ct = ctList; ct != NULL; ct = next)
+        {
+        next = ct->next;
+        if (ct->tdb != NULL && sameOk(trackDbSetting(ct->tdb, "blatResult"), "on"))
+            {
+            cartRemove(cart, ct->tdb->track);   /* no orphaned visibility for a reused ct_ id */
+            continue;   /* drop it; customTracksSaveCart below writes out only the kept list */
+            }
+        slAddHead(&keptList, ct);
+        }
+    slReverse(&keptList);
+    ctList = keptList;
+    }
+
 theCtList = customTrackAddToList(ctList, newCts, NULL, FALSE);
 
 customTracksSaveCart(database, cart, theCtList);
 
 /* Pin this bigPsl file in the cart so hgBlat's Table view can reopen exactly these results from a
  * shared session (see doShareReopen in hgBlat.c) - unambiguously, even when the cart holds several
  * BLAT custom tracks from earlier searches. */
 cartSetString(cart, "blatLastBigBed", bigBedFile);
 
 cartSetString(cart, "i", "PrintAllSequences");
 hgCustom(newCts->tdb->track, NULL);
 
 if (sameOk(cartOptionalString(cart, "autoRearr"), "1"))  
     {
     char snakeVar[256];