79e2e0421ffa1203d75e66351a2046085129528e
jcasper
  Thu Jun 15 15:16:16 2017 -0700
hgHubConnect now displays search details and indexes description content, refs #13625

diff --git src/hg/lib/hubSearchText.c src/hg/lib/hubSearchText.c
new file mode 100644
index 0000000..0a3575a
--- /dev/null
+++ src/hg/lib/hubSearchText.c
@@ -0,0 +1,236 @@
+/* hubSearchText.c was originally generated by the autoSql program, which also 
+ * generated hubSearchText.h and hubSearchText.sql.  This module links the database and
+ * the RAM representation of objects. */
+
+#include "common.h"
+#include "linefile.h"
+#include "dystring.h"
+#include "jksql.h"
+#include "rangeTree.h"
+#include "hubSearchText.h"
+
+
+
+char *hubSearchTextCommaSepFieldNames = "hubUrl,db,track,textLength,text";
+
+/* definitions for textLength column */
+static char *values_textLength[] = {"Short", "Long", NULL};
+static struct hash *valhash_textLength = NULL;
+
+void hubSearchTextStaticLoadWithNull(char **row, struct hubSearchText *ret)
+/* Load a row from hubSearchText table into ret.  The contents of ret will
+ * be replaced at the next call to this function. */
+{
+
+ret->hubUrl = row[0];
+ret->db = row[1];
+ret->track = row[2];
+ret->label = row[3];
+ret->textLength = sqlEnumParse(row[4], values_textLength, &valhash_textLength);
+ret->text = row[5];
+}
+
+struct hubSearchText *hubSearchTextLoadWithNull(char **row)
+/* Load a hubSearchText from row fetched with select * from hubSearchText
+ * from database.  Dispose of this with hubSearchTextFree(). */
+{
+struct hubSearchText *ret;
+
+AllocVar(ret);
+ret->hubUrl = cloneString(row[0]);
+ret->db = cloneString(row[1]);
+ret->track = cloneString(row[2]);
+ret->label = cloneString(row[3]);
+ret->textLength = sqlEnumParse(row[4], values_textLength, &valhash_textLength);
+ret->text = cloneString(row[5]);
+return ret;
+}
+
+struct hubSearchText *hubSearchTextLoadAll(char *fileName) 
+/* Load all hubSearchText from a whitespace-separated file.
+ * Dispose of this with hubSearchTextFreeList(). */
+{
+struct hubSearchText *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[6];
+
+while (lineFileRow(lf, row))
+    {
+    el = hubSearchTextLoadWithNull(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct hubSearchText *hubSearchTextLoadAllByChar(char *fileName, char chopper) 
+/* Load all hubSearchText from a chopper separated file.
+ * Dispose of this with hubSearchTextFreeList(). */
+{
+struct hubSearchText *list = NULL, *el;
+struct lineFile *lf = lineFileOpen(fileName, TRUE);
+char *row[6];
+
+while (lineFileNextCharRow(lf, chopper, row, ArraySize(row)))
+    {
+    el = hubSearchTextLoadWithNull(row);
+    slAddHead(&list, el);
+    }
+lineFileClose(&lf);
+slReverse(&list);
+return list;
+}
+
+struct hubSearchText *hubSearchTextCommaIn(char **pS, struct hubSearchText *ret)
+/* Create a hubSearchText out of a comma separated string. 
+ * This will fill in ret if non-null, otherwise will
+ * return a new hubSearchText */
+{
+char *s = *pS;
+
+if (ret == NULL)
+    AllocVar(ret);
+ret->hubUrl = sqlStringComma(&s);
+ret->db = sqlStringComma(&s);
+ret->track = sqlStringComma(&s);
+ret->label = sqlStringComma(&s);
+ret->textLength = sqlEnumComma(&s, values_textLength, &valhash_textLength);
+ret->text = sqlStringComma(&s);
+*pS = s;
+return ret;
+}
+
+void hubSearchTextFree(struct hubSearchText **pEl)
+/* Free a single dynamically allocated hubSearchText such as created
+ * with hubSearchTextLoad(). */
+{
+struct hubSearchText *el;
+
+if ((el = *pEl) == NULL) return;
+freeMem(el->hubUrl);
+freeMem(el->db);
+freeMem(el->track);
+freeMem(el->label);
+freeMem(el->text);
+freez(pEl);
+}
+
+void hubSearchTextFreeList(struct hubSearchText **pList)
+/* Free a list of dynamically allocated hubSearchText's */
+{
+struct hubSearchText *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    hubSearchTextFree(&el);
+    }
+*pList = NULL;
+}
+
+void hubSearchTextOutput(struct hubSearchText *el, FILE *f, char sep, char lastSep) 
+/* Print out hubSearchText.  Separate fields with sep. Follow last field with lastSep. */
+{
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->hubUrl);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->db);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->track);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->label);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+sqlEnumPrint(f, el->textLength, values_textLength);
+if (sep == ',') fputc('"',f);
+fputc(sep,f);
+if (sep == ',') fputc('"',f);
+fprintf(f, "%s", el->text);
+if (sep == ',') fputc('"',f);
+fputc(lastSep,f);
+}
+
+/* -------------------------------- End autoSql Generated Code -------------------------------- */
+
+/* Restrictions on the size of context chunks returned by getTextContext() */
+#define HST_MAXCONTEXTLENGTH 300
+#define HST_CONTEXTRADIUS 70
+
+static char *getTextContext(char *text, char *searchTerms)
+/* Look for instances of words from searchTerms in the supplied text, grab some surrounding
+ * context, and stitch them together into a string that combines overlapping regions. */
+{
+struct dyString *contextString = dyStringNew(0);
+struct rbTree *contextTree = rangeTreeNew();
+char *splitTerms[1024];
+char *cloneTerms = cloneString(searchTerms);
+if (isNotEmpty(cloneTerms))
+    strLower(cloneTerms);
+char *lowText = cloneString(text);
+if (isNotEmpty(lowText))
+    strLower(lowText);
+int termCount = chopByWhiteRespectDoubleQuotes(cloneTerms, splitTerms, 1024);
+int i;
+for (i=0; i<termCount; i++)
+    {
+    char *thisTerm = splitTerms[i];
+    if (thisTerm[0] == '"')
+        {
+        thisTerm++;
+        trimLastChar(thisTerm);
+        }
+    char *position = stringIn(thisTerm, lowText);
+    if (position == NULL)
+        continue;
+    int termStart = position - HST_CONTEXTRADIUS - lowText;
+    if (termStart < 0)
+        termStart = 0;
+    int termEnd = position + strlen(thisTerm) + HST_CONTEXTRADIUS - lowText;
+    if (termEnd > strlen(lowText))
+        termEnd = strlen(lowText);
+    rangeTreeAdd(contextTree, termStart, termEnd);
+    }
+struct range *rangeResult = rangeTreeList(contextTree);
+int cumulativeSize = 0;
+if (rangeResult != NULL)
+    dyStringPrintf(contextString, "...");
+while (rangeResult != NULL)
+    {
+    char contextChunk[HST_MAXCONTEXTLENGTH+1];
+    int copySize = rangeResult->end - rangeResult->start;
+    if (copySize > HST_MAXCONTEXTLENGTH)
+        copySize = HST_MAXCONTEXTLENGTH;
+    safencpy(contextChunk, sizeof(contextChunk), text+rangeResult->start, copySize);
+    dyStringPrintf(contextString, " %s ...", contextChunk);
+    cumulativeSize += copySize;
+    if (cumulativeSize >= HST_MAXCONTEXTLENGTH)
+        break;
+    rangeResult = rangeResult->next;
+    }
+return dyStringCannibalize(&contextString);
+}
+
+
+struct hubSearchText *hubSearchTextLoadWithNullGiveContext(char **row, char *searchTerms)
+/* Load a hubSearchText from row fetched with select * from hubSearchText
+ * from database, but instead of loading the entire text field for long text results,
+ * only load the pieces that provide context for the supplied searchTerms.
+ * Dispose of this with hubSearchTextFree(). */
+{
+struct hubSearchText *hst = hubSearchTextLoadWithNull(row);
+if (hst->textLength == hubSearchTextLong)
+    {
+    char *longTextContext = getTextContext(hst->text, searchTerms);
+    freeMem(hst->text);
+    hst->text = longTextContext;
+    }
+return hst;
+}