
__EmptyDoc:=
  rec(
    kind:="UNBOUND",
    name:="",
    sin:=[[]],
    sou:=[],
    short:="",
    sig:="",
    hash:="UNBOUND");

## Auxiliary

__CurryDisplayHookFun:=
  hook->
    (docrec->
      RunHookWithArg(hook,docrec));

___CurryPrintFun:=
  pre->
    (post->
      (fun->
        (function(args)
          local tmp;
          tmp:=fun(args);
          PrintString(pre);
          if tmp<>[] then
            if IsString(tmp) then
              PrintString(tmp);
            elif IsList(tmp) then
              Mapc(i->PrintString(i," "),tmp);
            elif tmp = FAILURE then
              return VOID;
            else
              PrintString(tmp);
            fi;
          fi;
          PrintString(post);
        end)));

___CurryPrintFunIf:=
  pre->
    (post->
      (fun->
        (function(args)
          local tmp;
          tmp:=fun(args);
          if tmp<>"" and tmp<>false and tmp<>[] then
            PrintString(pre);
            if IsString(tmp) then
              PrintString(tmp);
            elif IsList(tmp) then
              Mapc(i->PrintString(i," "),tmp);
            elif tmp=FAILURE then
              PrintString("");
            else
              PrintString(tmp);
            fi;
            PrintString(post);
          fi;
        end)));

__CurryPrintFun:=___CurryPrintFun("");
__CurryPrintFunIf:=___CurryPrintFunIf("");
__CurryPrintFunNL:=__CurryPrintFun("\n");
__CurryPrintFun1L:=__CurryPrintFun(": ");
__CurryPrintFunNLie:=__CurryPrintFunIf("\n");
__CurryPrintFun1Lie:=__CurryPrintFunIf(": ");

___CurryPrintFunFC:=
  prfun->
    (pre->
      (post->
        (fun->
          (function(args)
            local tmp;
            tmp:=fun(args);
            if tmp<>"" and tmp<>false and tmp<>FAILURE then
              PrintString(pre);
              prfun(_Filtered_func_list(i->IsSuccess(i),tmp));
              PrintString(post);
            fi;
          end))));



### less main funs

RetrieveDocumentation:=_Function_alist(__DOC,rec(Fail:=FAILURE));
InstallDocumentation(
  rec(
    kind:="FUNCTION",
    name:="RetrieveDocumentation",
    sin  := [[string,"dochash"]],
    sou  := [[record]],
    short := "Retrieve the current entry for `dochash' in the global "+
      "documentation.\n"+
      "Use this function to obtain the entire record from __DOC as is.",
    ex := ["RetrieveDocumentation(\""+
           DocGenHashByString("RetrieveDocumentation(string)")+
           "\");"]), rec());

ExistsDocumentation:=hash->IsSuccess(_Position_alist_any(__DOC,hash));
InstallDocumentation(
  rec(
    kind:="FUNCTION",
    name:="ExistsDocumentation",
    sin  := [[string,"dochash"]],
    sou  := [[elt-alg^boo]],
    short := "Return true iff documentation for 'dochash' is available."), rec());



__RetrieveDocField:=
  field->
    (docrec->
      _GetEntry_rec_string(docrec,field,rec(Fail:=[])));


## forward declaration (in lack of backquoting)
if not(IsBound(DisplayDocsSig)) then
  DisplayDocsSig:=
    function(i) Print("hehe\n");
  end;
fi;


###
### Display atom funs
###
## The master display function
__InstallDocDisplay:=
  function(field)
    EvalString("_RetrieveDoc"+Camelcase(field)+":=__RetrieveDocField(\""+Downcase(field)+"\")");
    EvalString("_DisplayDoc"+Camelcase(field)+"NL:=__CurryPrintFunNL(_RetrieveDoc"+Camelcase(field)+")");
    EvalString("_DisplayDoc"+Camelcase(field)+"1L:=__CurryPrintFun1L(_RetrieveDoc"+Camelcase(field)+")");
    EvalString("_DisplayDoc"+Camelcase(field)+"NLie:=__CurryPrintFunNLie(_RetrieveDoc"+Camelcase(field)+")");
    EvalString("_DisplayDoc"+Camelcase(field)+"1Lie:=__CurryPrintFun1Lie(_RetrieveDoc"+Camelcase(field)+")");
    EvalString("_DisplayDoc"+Camelcase(field)+":=sep->__CurryPrintFun(sep)(_RetrieveDoc"+Camelcase(field)+")");
  end;

__InstallDocDisplay("sig");
__InstallDocDisplay("sog");

_RetrieveDocHash:=__RetrieveDocField("hash");
_DisplayDocHashOV:=___CurryPrintFun("[0;1m#")("[0;0m: ")(_RetrieveDocHash);
_DisplayDocHashNL:=___CurryPrintFun("[0;0m#")("\n")(_RetrieveDocHash);
_DisplayDocHash1L:=___CurryPrintFun("[0;0m#")(": ")(_RetrieveDocHash);
_DisplayDocHash:=sep->___CurryPrintFun("[0;0m#")(sep)(_RetrieveDocHash);

_RetrieveDocPos:=
  function(docrec)
    local pos;
    pos:=_Position_alist_any(__DOC,_GetEntry_rec_string(docrec,"hash",rec(Fail:=FAILURE)),rec(Fail:="----"));
    pos:=SPrint(pos);
    return (4-_Size_list(pos))*"0"+pos;
  end;
_DisplayDocPosOV:=___CurryPrintFun("[0;1m")("[0;0m: ")(_RetrieveDocPos);
_DisplayDocPosNL:=___CurryPrintFun("[0;0m")("\n")(_RetrieveDocPos);
_DisplayDocPos1L:=___CurryPrintFun("[0;0m")(": ")(_RetrieveDocPos);
_DisplayDocPosParen:=sep->___CurryPrintFun("[0;0m(")("[0;0m)"+sep)(_RetrieveDocPos);
_DisplayDocPos:=sep->___CurryPrintFun("[0;0m")(sep)(_RetrieveDocPos);

_RetrieveDocKind:=__RetrieveDocField("kind");
_DisplayDocKindNL:=___CurryPrintFun("[0;1m")("[0;0m\n")(_RetrieveDocKind);
_DisplayDocKind1L:=___CurryPrintFun("[0;1m")("[0;0m:")(_RetrieveDocKind);
_DisplayDocKindNLie:=__CurryPrintFunNLie(_RetrieveDocKind);
_DisplayDocKind1Lie:=__CurryPrintFun1Lie(_RetrieveDocKind);
_DisplayDocKind:=sep->___CurryPrintFun("[0;1m")("[0;0m"+sep)(_RetrieveDocKind);


_RetrieveDocSyntax:=__RetrieveDocField("syntax");
_DisplayDocSyntaxNL:=___CurryPrintFunIf("\n[0;1mSYNTAX:[0;0m\n")("\n")(_RetrieveDocSyntax);
_DisplayDocSyntax1L:=___CurryPrintFunIf("\nSYNTAX:")(": ")(_RetrieveDocSyntax);
_DisplayDocSyntax:=sep->___CurryPrintFunIf("\nSYNTAX:\n")(sep)(_RetrieveDocSyntax);


_RetrieveDocShort:=__RetrieveDocField("short");
_DisplayDocShortNL:=___CurryPrintFunIf("[0;1mPURPOSE:[0;0m\n")("\n")(_RetrieveDocShort);
_DisplayDocShort1L:=___CurryPrintFunIf("PURPOSE:")(": ")(_RetrieveDocShort);
_DisplayDocShort:=sep->___CurryPrintFunIf("PURPOSE:\n")(sep)(_RetrieveDocShort);


_RetrieveDocEx:=docrec->_Mapconcat_func_list_string(i->i,__RetrieveDocField("ex")(docrec),"\n\n");
_DisplayDocExNL:=___CurryPrintFunIf("[0;1mEXAMPLE:[0;0m\n")("\n\n")(_RetrieveDocEx);
_DisplayDocEx:=sep->___CurryPrintFunIf("EXAMPLE:\n")(sep)(_RetrieveDocEx);


_RetrieveDocSource:=__RetrieveDocField("docsrc");
_DisplayDocSourceNL:=___CurryPrintFunIf("[0;1mSOURCE FILES:[0;0m\n")("\n")(_RetrieveDocSource);
_DisplayDocSource1L:=___CurryPrintFunIf("SOURCE FILES:")(": ")(_RetrieveDocSource);
_DisplayDocSourceNL:=___CurryPrintFunIf("[0;1mSOURCE FILES:[0;0m\n")("\n\n")(_RetrieveDocSource);
_DisplayDocSource:=sep->___CurryPrintFunIf("SOURCE FILES:\n")(sep)(_RetrieveDocSource);


_RetrieveDocCite:=__RetrieveDocField("cite");
_DisplayDocCiteNL:=___CurryPrintFunIf("[0;1mREFERENCES:[0;0m\n")("\n")(_RetrieveDocCite);
_DisplayDocCite1L:=___CurryPrintFunIf("REFERENCES:")(": ")(_RetrieveDocCite);
_DisplayDocCiteNL:=___CurryPrintFunIf("[0;1mREFERENCES:[0;0m\n")("\n\n")(_RetrieveDocCite);
_DisplayDocCite:=sep->___CurryPrintFunIf("REFERENCES:\n")(sep)(_RetrieveDocCite);


## forward declare
_RetrieveDocSee:=docrec->_Mapconcat_func_list_string(i->"#"+i,__RetrieveDocField("see")(docrec),", ");
_RetrieveDocSeeLookup:=docrec->_Apply_list_func(__RetrieveDocField("see")(docrec),i->RetrieveDocumentation(i));
_DisplayDocSeeNL:=___CurryPrintFunIf("SEE ALSO:  ")("\n\n")(_RetrieveDocSee);
_DisplayDocSee1L:=___CurryPrintFunIf("SEE ALSO: ")("; ")(_RetrieveDocSee);
_DisplayDocSeeLU:=___CurryPrintFunFC(DisplayDocsSig)("\nSEE ALSO:\n\n")("\n\n")(_RetrieveDocSeeLookup);
_DisplayDocSee:=sep->___CurryPrintFunFC(DisplayDocsSig)("[0;1mSEE ALSO:[0;0m\n")(sep)(_RetrieveDocSeeLookup);

## handling of optional arguments
_RetrieveDocOpt:=docrec->_Mapconcat_func_list_string(i->""+_GenerateDocSinAtom2(i)+"",__RetrieveDocField("opt")(docrec),"\n");
_DisplayDocOptNLie:=___CurryPrintFunIf("\n[0;1mOPTIONAL ARGUMENTS:[0;0m\n")("\n")(_RetrieveDocOpt);


## obscure general display funs
_DisplayDoc:=sep->(field->__CurryPrintFun(sep)(__RetrieveDocField(field)));
_EmptyNL:=
  function(arg)
    Print("\n");
  end;
_Indent1L:=
  function(arg)
    Print("         ");
  end;


###
### Display Functions
### 
## Some hooks
DisplayDocSigFormatHook:=
  [
   _DisplayDocPos1L,_DisplayDocSig(""),_DisplayDocSogNL];
DisplayDocSigShortFormatHook:=
  [
   _DisplayDocPos1L,_DisplayDocKind1L,_DisplayDocSig(""),_DisplayDocSogNL,
   _DisplayDocShortNL];
DisplayDocSigShortOneLineFormatHook:=
  [
   _DisplayDocPos1L,_DisplayDocKind1L,_DisplayDocSig(""),_DisplayDocSog1L,_DisplayDocShortNL];
DisplayDocCompleteFormatHook:=
  [
   _DisplayDocHashOV,_DisplayDocKind(" "),_DisplayDocPosParen("\n"),
   _DisplayDocSig(""),_DisplayDocSogNL,
   _DisplayDocSyntaxNL,
   _DisplayDocOptNLie,
   _EmptyNL,
   _DisplayDocShortNL,
   _EmptyNL,
   _DisplayDocExNL,
   _DisplayDocSourceNL,
   _DisplayDocCiteNL,
   _DisplayDocSee("\n")];


## MAIN DISPLAY FUNCTIONS
DisplayDocSig:=__CurryDisplayHookFun(DisplayDocSigFormatHook);
DisplayDocShort:=__CurryDisplayHookFun(DisplayDocSigShortFormatHook);
DisplayDocShort1L:=__CurryDisplayHookFun(DisplayDocSigShortOneLineFormatHook);
DisplayDocComplete:=__CurryDisplayHookFun(DisplayDocCompleteFormatHook);


## higher level function for more than 1 docrec
_DisplayDocs:=
   dispfun->
     (dreclist->
        Mapc(dispfun,dreclist));
DisplayDocsSig:=_DisplayDocs(DisplayDocSig);
DisplayDocsSig2:=_DisplayDocs(DisplayDocSig);
DisplayDocsShort:=_DisplayDocs(DisplayDocShort);
DisplayDocsShort1L:=_DisplayDocs(DisplayDocShort1L);


## default functions
DisplayDoc:=DisplayDocShort1L;
DisplayDocs:=DisplayDocsShort1L;




## now the most important, the documentation of the documentation ;)

InstallDocumentation(
  rec(
    kind:="FUNCTION",
    name:="DisplayDocSig",
    sin:=[[string,"dochash"]],
    sou:=[],
    short:="Display name and signature for `dochash' which must be a valid \
hash in the internal documentation.",
    see:=[DocGenHashByString("DisplayDocShort(string)"),
          DocGenHashByString("DisplayDocComplete(string)")],
    ex:=["DisplayDocSig(\""+DocGenHashByString("DisplayDocSig(string)")+"\");"]),rec());
InstallDocumentation(
  rec(
    kind:="FUNCTION",
    name:="DisplayDocShort",
    sin:=[[string,"dochash"]],
    sou:=[],
    short:="Display name, signature and shortdoc (if existing) for `dochash'.",
    see:=[DocGenHashByString("DisplayDocSig(string)"),
          DocGenHashByString("DisplayDocComplete(string)")],
    ex:=["DisplayDocShort(\""+DocGenHashByString("DisplayDocShort(string)")+"\");"]),rec());
InstallDocumentation(
  rec(
    kind:="FUNCTION",
    name:="DisplayDocComplete",
    sin:=[[string,"dochash"]],
    sou:=[],
    short:="Display name, signature and everything else for `dochash'.",
    see:=[DocGenHashByString("DisplayDocSig(string)"),
          DocGenHashByString("DisplayDocShort(string)")],
    ex:=["DisplayDocComplete(\""+DocGenHashByString("DisplayDocComplete(string)")+"\");"]),rec());




###
### Higher level Retrieve Funs
###
## You can retrieve a dochash or a list of dochashes with them here

_FindByPos:=
  (pos->
    __DOC[pos]);
_FindBySexp:=
  field->
    (sexp->
      _Filtered_list_func(__DOC,i->sexp=i.(field)));
_FindByISexp:=
  field->
    (sexp->
      _Filtered_list_func(__DOC,i->Downcase(sexp)=Downcase(i.(field))));
_FindBySexpAndKind:=
  kind->
    (field->
      (sexp->
        _Filtered_list_func(_FindBySexp(field)(sexp),i->i.kind=kind)));
_FindByISexpAndKind:=
  kind->
    (field->
      (sexp->
        _Filtered_list_func(_FindBySexp(field)(sexp),i->i.kind=kind)));
_FindByRexp:=
  field->
    (rexp->
      _Filtered_list_func(__DOC,i->IsMatching(rexp,i.(field))));
_FindByIRexp:=
  field->
    (rexp->
      _Filtered_list_func(__DOC,i->IsMatching(Downcase(rexp),Downcase(i.(field)))));


_IfFieldBoundp:=
  function(record,field,default)
    local prfun,gr;
    prfun:=
      function(lit)
        if Type(lit)=string then
          return lit;
        elif IsList(lit) then
          return _Mapconcat_func_list(i->prfun(i),lit);
        else
          return default;
        fi;
      end;

    gr := _GetEntry_rec_string(record,field,rec(Fail:=FAILURE));
    if gr=FAILURE then
      return default;
    else
      return prfun(gr);
    fi;
  end;
_FindByRexps:=
  fields->
    (rexp->
      _Filtered_list_func(__DOC,i->_ForAny_list_func(fields,j->IsMatching(rexp,_IfFieldBoundp(i,j,"")))));
_FindByIRexps:=
  fields->
    (rexp->
      _Filtered_list_func(__DOC,i->_ForAny_list_func(fields,j->IsMatching(Downcase(rexp),Downcase(_IfFieldBoundp(i,j,""))))));
_FindByRexpAndKind:=
  kind->
    (field->
      (rexp->
        _Filtered_list_func(_FindByRexp(field)(rexp),i->i.kind=kind)));
_FindByIRexpAndKind:=
  kind->
    (field->
      (rexp->
        _Filtered_list_func(_FindByIRexp(field)(rexp),i->i.kind=kind)));
_FindByRexpsAndKind:=
  kind->
    (fields->
      (rexp->
        _Filtered_list_func(_FindByRexps(fields)(rexp),i->i.kind=kind)));
_FindByIRexpsAndKind:=
  kind->
    (fields->
      (rexp->
        _Filtered_list_func(_FindByIRexps(fields)(rexp),i->i.kind=kind)));


DocFindNames:=_FindByISexp("name");
DocFindNamesCS:=_FindBySexp("name");
DocFindNamesLimitTo:=kind->_FindByISexpAndKind(kind)("name");
DocFindNamesCSLimitTo:=kind->_FindBySexpAndKind(kind)("name");

DocFindMatchingNames:=_FindByIRexp("name");
DocFindMatchingNamesCS:=_FindByRexp("name");
DocFindMatchingNamesLimitTo:=kind->_FindByIRexpAndKind(kind)("name");
DocFindMatchingNamesCSLimitTo:=kind->_FindByRexpAndKind(kind)("name");

DocFindMatchingNamesOrShort:=_FindByIRexps(["name","short","opt"]);
DocFindMatchingNamesOrShortCS:=_FindByRexps(["name","short","opt"]);
DocFindMatchingNamesOrShortLimitTo:=kind->_FindByIRexpsAndKind(kind)(["name","short","opt","ex"]);
DocFindMatchingNamesOrShortCSLimitTo:=kind->_FindByRexpsAndKind(kind)(["name","short","opt","ex"]);


##Mapc(i->EvalString("DocFind"+Camelcase(i)+"Names:=_FindByISexpAndKind(\""+ i + "\")(\"name\")"),__DocumentationKinds);
##Mapc(i->EvalString("DocFind"+Camelcase(i)+"NamesCS:=_FindBySexpAndKind(\""+ i + "\")(\"name\")"),__DocumentationKinds);

##Mapc(i->EvalString("DocFindMatching"+Camelcase(i)+"Names:=_FindByIRexpAndKind(\""+ i + "\")(\"name\")"),__DocumentationKinds);
##Mapc(i->EvalString("DocFindMatching"+Camelcase(i)+"NamesCS:=_FindByRexpAndKind(\""+ i + "\")(\"name\")"),__DocumentationKinds);



DocDisplayMatching:=
  rexp->
    Mapc(DisplayDocShort,DocFindMatchingNames(rexp));

##Mapc(i->EvalString("DocDisplayMatching"+Camelcase(i)+"s:=rexp->Mapc(DisplayDocShort1L,DocFindMatching"+Camelcase(i)+"Names(rexp))"),__DocumentationKinds);





### signature
# 
__DocFindMatchingSignatures:=
  record->
    (field->
      (function(arg)
        local A,match,typ,I;
        match:=[];
        if _Size_list(arg)=0 then
          typ:=void;
        elif _Size_list(arg)=1 then
          typ:=arg[1];
        else
          return match;
        fi;
        for A in record do
          if IsBound(A.(field)) and IsList(A.(field)) then
            for I in A.(field) do
              if IsList(I) and IsBound(I[1]) then
                if I[1]=typ then
                  _Add__list_any(match,A);
                fi;
              elif typ=void then
                _Add__list_any(match,A);
              fi;
            od;
          fi;
        od;
        return match;
      end));
_DocFindMatchingSignatures:=__DocFindMatchingSignatures(__DOC);
_DocDisplayMatchingSignatures:=
  field->
    (type->
       Mapc(DisplayDocSig,_DocFindMatchingSignatures(field)(type)));


DocFindMatchingSignaturesIn:=_DocFindMatchingSignatures("sin");
DocDisplayMatchingSignaturesIn:=_DocDisplayMatchingSignatures("sin");

DocFindMatchingSignaturesOut:=_DocFindMatchingSignatures("sin");
DocDisplayMatchingSignaturesOut:=_DocDisplayMatchingSignatures("sou");


DisplayDocShortThreshold:=1;


#############################################################################
##
#F  Help( <various> )
##
Help:=i->i; ## just a dummy
_ParseHelp:=
  function(search)
    local typ, submatch, lim, limp, gather, i;
  
    gather:=[];
    limp:=false;

  ### search by hash
    submatch:=StringMatch("^#*\\([0-9a-f]\\{6\\}\\)$",Downcase(search));
    if IsBound(submatch[2]) then
      gather:=[RetrieveDocumentation(submatch[2])];
    fi;
  
    ## if more than one hash
    submatch:=StringMatch("^\\(.*\\)[, :]+#*\\([0-9a-f]\\{6\\}\\)",Downcase(search));
    if IsBound(submatch[3]) then
      Help(submatch[2]);
      gather:=[RetrieveDocumentation(submatch[3])];
    fi;


  ### search by pos
    submatch:=StringMatch("^\\([0-9]\\{1,4\\}\\)$",search);
    if IsBound(submatch[2]) then
      i:=EvalString(submatch[2]);
      gather:=[_GetEntry_list_eor(__DOC,i,rec(Fail:=""))];
    fi;
  
    ## if more than one pos
    submatch:=StringMatch("^\\(.*\\)[, :]+\\([0-9]\\{1,4\\}\\)",search);
    if IsBound(submatch[3]) then
      Help(submatch[2]);
      i:=EvalString(submatch[3]);
      gather:=[_GetEntry_list_eor(__DOC,i,rec(Fail:=""))];
    fi;


    lim:=__DOC;
    submatch:=StringMatch("(\\(.*\\))",search);
    if not(_GetEntry_list_eor(submatch,2,rec(Fail:=""))="") then
      submatch:=Split(submatch[2],",");
      if _GetEntry_list_eor(submatch,1,rec(Fail:=""))="" then
        submatch:=["void"];
      fi;
      typ := _Apply_func_list(EvalString,submatch);
      if _ForAny_list_func(typ,i->Type(i)<>type) then
        Print("?(<type>) expected.\n");
        typ:=[];
        lim:=[];
      fi;
      for i in typ do
        lim:=__DocFindMatchingSignatures(lim)("sin")(i);
      od;
      limp:=true;
    fi;
  
    submatch:=StringMatch("->\\([^ ]*\\)",search);
    if not(_GetEntry_list_eor(submatch,2,rec(Fail:=""))="") then
      submatch:=Split(submatch[2],",");
      if _GetEntry_list_eor(submatch,1,rec(Fail:=""))="" then
        submatch:=["void"];
      fi;
      typ := _Apply_func_list(EvalString,submatch);
      if _ForAny_list_func(typ,i->Type(i)<>type) then
        Print("?-><type> expected.\n");
        typ:=[];
        lim:=[];
      fi;
      for i in typ do
        lim:=__DocFindMatchingSignatures(lim)("sou")(i);
      od;
      limp:=true;
    fi;
    if limp then
      gather:=lim;
    fi;
  
  
    ## general string searches
    submatch:=StringMatch("^\\(.\\)\\(.+\\)|\\(.*\\)",search);
    if IsBound(submatch[3]) then
  
      if (submatch[2]="*") then
        gather:=DocFindMatchingNamesOrShortLimitTo(Upcase(submatch[4]))(submatch[3]);
  
      elif (submatch[2]="!") then
        gather:=DocFindMatchingNamesLimitTo(Upcase(submatch[4]))(submatch[3]);
  
      elif (submatch[2]="^") then
        gather:=DocFindMatchingNamesLimitTo(Upcase(submatch[4]))("^"+submatch[3]);
  
      else
        gather:=DocFindNamesLimitTo(Upcase(submatch[3]))(submatch[2]+submatch[3]);
      fi;
  
    else
  
      ## now match again, but w/o the | operator
      submatch:=StringMatch("^\\(.\\)\\(.+\\)",search);
      if not(_GetEntry_list_eor(submatch,3,rec(Fail:=""))="") then
    
        if (submatch[2]="*") then
          gather:=DocFindMatchingNamesOrShort(submatch[3]);
    
        elif (submatch[2]="!") then
          gather:=DocFindMatchingNames(submatch[3]);
    
        elif (submatch[2]="^") then
          gather:=DocFindMatchingNames("^"+submatch[3]);
        fi;
    
      fi;
  
    fi;
    
    Append_(gather,DocFindNames(search));
  
    return gather;
  end;


Help := function(query)
local search, submatch, gather;

  search := Copy(query);

  ## cleansing query
  submatch:=StringMatch("^[ \t]*",search);
  if IsBound(submatch[1]) then
    search:=search{[_Size_list(submatch[1])+1.._Size_list(search)]};
  fi;

  submatch:=StringMatch("[ \t]*;?$",search);
  if IsBound(submatch[1]) then
    search:=search{[1.._Size_list(search)-_Size_list(submatch[1])]};
  fi;

  if search="" or search=";" then
    search:="Help";
  fi;


  ## parsing
  gather:=_Filtered_list_func(_ParseHelp(search),i->i<>__EmptyDoc);

  ## output
  if _Size_list(gather)=0 then
    PrintString("\nNo matches.\nMaybe try ?*<string>.\n");
  elif _Size_list(gather)<=DisplayDocShortThreshold then
    Print("\n");
    Mapc(DisplayDocComplete,gather);
  else
    Print("\n");
    Mapc(DisplayDocSig,gather);
    Print("\n");
  fi;
end;


if _DocDebug and not(QUIET) and not(IsBound(__looserefswarned)) then
  __LooseRefs:=_Filtered_func_list(i->_ForAny_list_func(_GetEntry_rec_string(i,"see",rec(Fail:=[])),k->not(ExistsDocumentation(k))),__DOC);
  if _Size_list(__LooseRefs)>0 then
    PrintString("\n");
    PrintString("##############################################################################\n");
    PrintString("## Nirvana references in see fields detected.                               ##\n");
    PrintString("## See `Apply(i->i.hash,__LooseRefs);' for a list of the referring entries. ##\n");
    PrintString("##############################################################################\n");
  fi;
  __looserefswarned:=true;
fi;
