af3a143571e5aa064eab75c34f9444b35413b562 chmalee Tue Nov 30 15:28:15 2021 -0800 Add snippet support to trix searching. Required changing the wordPos from the first highest matching wordIndex to the wordIndex of the actual span. Have trixContextIndex create a second level index for fast retrieval of line offsets in original text file used by ixIxx. Create a simple UI for navigating hgFind search results. diff --git src/hg/cgilib/cartJson.c src/hg/cgilib/cartJson.c index 2d504ff..8c0914e 100644 --- src/hg/cgilib/cartJson.c +++ src/hg/cgilib/cartJson.c @@ -55,122 +55,131 @@ { regmatch_t matches[3]; if (regexMatchSubstrNoCase(textIn, "<a href[^>]+>", matches, ArraySize(matches))) { char *textOut = cloneString(textIn); memmove(textOut+matches[0].rm_so, textOut+matches[0].rm_eo, strlen(textOut) + 1 - matches[0].rm_eo); if (regexMatchSubstrNoCase(textOut, "</a>", matches, ArraySize(matches))) memmove(textOut+matches[0].rm_so, textOut+matches[0].rm_eo, strlen(textOut) + 1 - matches[0].rm_eo); return textOut; } return textIn; } -static void hgPositionsJson(struct jsonWrite *jw, char *db, struct hgPositions *hgp, struct cart *cart) +void hgPositionsJson(struct jsonWrite *jw, char *db, struct hgPositions *hgp, struct cart *cart) /* Write out JSON description of multiple position matches. */ { struct hgPosTable *table; jsonWriteListStart(jw, "positionMatches"); struct trackDb *tdbList = NULL; for (table = hgp->tableList; table != NULL; table = table->next) { if (table->posList != NULL) { - char *tableName = table->name; + char *trackName = table->name, *tableName = table->name; + struct trackDb *tdb = NULL; // clear the tdb cache if this track is a hub track + if (! (sameString("trackDb", tableName) || sameString("helpDocs", tableName) || sameString("publicHubs", tableName))) + { if (isHubTrack(tableName)) tdbList = NULL; - struct trackDb *tdb = tdbForTrack(db, tableName, &tdbList); + tdb = tdbForTrack(db, tableName, &tdbList); if (!tdb && startsWith("all_", tableName)) tdb = tdbForTrack(db, tableName+strlen("all_"), &tdbList); if (!tdb) errAbort("no track for table \"%s\" found via a findSpec", tableName); - char *trackName = tdb->track; + trackName = tdb->track; + } jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "name", table->name); jsonWriteString(jw, "trackName", trackName); jsonWriteString(jw, "description", table->description); + if (tdb != NULL) jsonWriteString(jw, "vis", hCarefulTrackOpenVis(db, trackName)); jsonWriteListStart(jw, "matches"); struct hgPos *pos; for (pos = table->posList; pos != NULL; pos = pos->next) { char *encMatches = cgiEncode(pos->browserName); jsonWriteObjectStart(jw, NULL); // begin one match if (pos->chrom != NULL) jsonWriteStringf(jw, "position", "%s:%d-%d", pos->chrom, pos->chromStart+1, pos->chromEnd); else // GenBank results set position to GB accession instead of chr:s-e position. jsonWriteString(jw, "position", pos->name); // this is magic to tell the browser to make the // composite and this subTrack visible - if (tdb->parent) + if (tdb && tdb->parent) { if (tdbIsSuperTrackChild(tdb)) jsonWriteStringf(jw, "extraSel", "%s=show&", tdb->parent->track); else { // tdb is a subtrack of a composite or a view jsonWriteStringf(jw, "extraSel", "%s_sel=1&%s_sel=1&", trackName, tdb->parent->track); } } jsonWriteString(jw, "hgFindMatches", encMatches); jsonWriteString(jw, "posName", htmlEncode(pos->name)); + jsonWriteBoolean(jw, "canonical", pos->canonical); if (pos->description) { stripString(pos->description, "\n"); jsonWriteString(jw, "description", stripAnchor(pos->description)); } jsonWriteObjectEnd(jw); // end one match } jsonWriteListEnd(jw); // end matches + if (table->searchTime != 0) + jsonWriteNumber(jw, "searchTime", table->searchTime); jsonWriteObjectEnd(jw); // end one table } } jsonWriteListEnd(jw); // end positionMatches } static struct hgPositions *genomePosCJ(struct jsonWrite *jw, char *db, char *spec, char **retChromName, int *retWinStart, int *retWinEnd, struct cart *cart) /* Search for positions in genome that match user query. * Return an hgp unless there is a problem. hgp->singlePos will be set if a single * position matched. * Otherwise display list of positions, put # of positions in retWinStart, * and return NULL. */ { char *hgAppName = "cartJson"; struct hgPositions *hgp = NULL; char *chrom = NULL; int start = BIGNUM; int end = 0; +boolean measureTiming = cartUsualBoolean(cart, "measureTiming", FALSE); char *terms[16]; int termCount = chopByChar(cloneString(spec), ';', terms, ArraySize(terms)); boolean multiTerm = (termCount > 1); int i = 0; for (i = 0; i < termCount; i++) { trimSpaces(terms[i]); if (isEmpty(terms[i])) continue; - hgp = hgPositionsFind(db, terms[i], "", hgAppName, cart, multiTerm); + hgp = hgPositionsFind(db, terms[i], "", hgAppName, cart, multiTerm, measureTiming, NULL); if (hgp == NULL || hgp->posCount == 0) { jsonWriteStringf(jw, "error", "Sorry, couldn't locate %s in %s %s", htmlEncode(terms[i]), trackHubSkipHubName(hOrganism(db)), hFreezeDate(db)); if (multiTerm) jsonWriteStringf(jw, "error", "%s not uniquely determined -- can't do multi-position search.", terms[i]); *retWinStart = 0; return NULL; } if (hgp->singlePos != NULL) { if (chrom != NULL && !sameString(chrom, hgp->singlePos->chrom))