It has two modes.
-Without the -http flag, it prints plain text documentation to standard output and exits.
+Without the -http flag, it runs in command-line mode and prints plain text
+documentation to standard output and exits.
godoc fmt
godoc fmt Printf
-With the -http flag, it runs as a web server and presents the documentation as a web page.
+In command-line mode, the -q flag enables search queries against a godoc running
+as a webserver. If no explicit server address is specified with the -server flag,
+godoc first tries localhost:6060 and then http://golang.org.
+
+ godoc -q Reader Writer
+ godoc -q math.Sin
+ godoc -server=:6666 -q sin
+
+With the -http flag, it runs as a web server and presents the documentation as a
+web page.
godoc -http=:6060
The flags are:
-v
verbose mode
+ -q
+ arguments are considered search queries: a legal query is a
+ single identifier (such as ToLower) or a qualified identifier
+ (such as math.Sin).
-src
print exported source in command-line mode
-tabwidth=4
print HTML in command-line mode
-goroot=$GOROOT
Go root directory
- -http=
+ -http=addr
HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
+ -server=addr
+ webserver address for command line searches
-sync="command"
if this and -sync_minutes are set, run the argument as a
command every sync_minutes; it is intended to update the
// Template formatter for "infoLine" format.
func infoLineFmt(w io.Writer, x interface{}, format string) {
+ // TODO(gri) The code below won't work when invoked
+ // as part of a command-line search where
+ // there is no index (and thus Snippets).
+ // At the moment, the search.txt template
+ // is not using this formatter and cannot
+ // show line numbers.
info := x.(SpotInfo)
line := info.Lori()
if info.IsIndex() {
packageHTML,
packageText,
searchHTML,
+ searchText,
sourceHTML *template.Template
)
packageHTML = readTemplate("package.html")
packageText = readTemplate("package.txt")
searchHTML = readTemplate("search.html")
+ searchText = readTemplate("search.txt")
sourceHTML = readTemplate("source.html")
}
Accurate bool
}
-func search(c *http.Conn, r *http.Request) {
- query := strings.TrimSpace(r.FormValue("q"))
- var result SearchResult
+func lookup(query string) (result SearchResult) {
+ result.Query = query
if index, timestamp := searchIndex.get(); index != nil {
- result.Query = query
result.Hit, result.Alt, result.Illegal = index.(*Index).Lookup(query)
_, ts := fsTree.get()
result.Accurate = timestamp >= ts
}
+ return
+}
+
+
+func search(c *http.Conn, r *http.Request) {
+ query := strings.TrimSpace(r.FormValue("q"))
+ result := lookup(query)
var title string
if result.Hit != nil {
time.Sleep(1 * 60e9) // try once a minute
}
}
+
+
+// ----------------------------------------------------------------------------
+// IndexServer
+
+type Query struct {
+ Query string
+}
+
+
+type IndexServer struct{}
+
+
+func (s *IndexServer) Lookup(query *Query, result *SearchResult) os.Error {
+ *result = lookup(query.Query)
+ return nil
+}
"log"
"os"
pathutil "path"
+ "rpc"
"time"
)
+const (
+ defaultAddr = ":6060" // default webserver address
+ golangAddr = "golang.org:http"
+)
+
var (
// periodic sync
syncCmd = flag.String("sync", "", "sync command; disabled if empty")
syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
syncDelay delayTime // actual sync delay in minutes; usually syncDelay == syncMin, but delay may back off exponentially
- // server control
- httpaddr = flag.String("http", "", "HTTP service address (e.g., ':6060')")
+ // network
+ httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
+ serverAddr = flag.String("server", "", "webserver address for command line searches")
// layout control
html = flag.Bool("html", false, "print HTML in command-line mode")
genAST = flag.Bool("src", false, "print exported source in command-line mode")
+
+ // command-line searches
+ query = flag.Bool("q", false, "arguments are considered search queries")
)
func usage() {
fmt.Fprintf(os.Stderr,
"usage: godoc package [name ...]\n"+
- " godoc -http=:6060\n")
+ " godoc -http="+defaultAddr+"\n")
flag.PrintDefaults()
os.Exit(2)
}
}
+func remoteLookup(query string) (result *SearchResult, err os.Error) {
+ var client *rpc.Client
+ if *serverAddr != "" {
+ // try server only
+ client, err = rpc.DialHTTP("tcp", *serverAddr)
+ if err != nil {
+ return
+ }
+ } else {
+ // try local default client first, followed by golang.org
+ client, err = rpc.DialHTTP("tcp", defaultAddr)
+ if err != nil {
+ log.Stderrf("trying %s (no local webserver found at %s)", golangAddr, defaultAddr)
+ client, err = rpc.Dial("tcp", golangAddr)
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ result = new(SearchResult)
+ err = client.Call("IndexServer.Lookup", &Query{query}, result)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+
func main() {
flag.Usage = usage
flag.Parse()
// Check usage: either server and no args, or command line and args
- if (*httpaddr != "") != (flag.NArg() == 0) {
+ if (*httpAddr != "") != (flag.NArg() == 0) {
usage()
}
initHandlers()
readTemplates()
- if *httpaddr != "" {
+ if *httpAddr != "" {
// HTTP server mode.
var handler http.Handler = http.DefaultServeMux
if *verbose {
log.Stderrf("Go Documentation Server\n")
- log.Stderrf("address = %s\n", *httpaddr)
+ log.Stderrf("address = %s\n", *httpAddr)
log.Stderrf("goroot = %s\n", goroot)
log.Stderrf("tabwidth = %d\n", *tabwidth)
if !fsMap.IsEmpty() {
// TODO(gri): Do we still need this?
time.Sleep(1e9)
+ // Register index server.
+ rpc.Register(new(IndexServer))
+ rpc.HandleHTTP()
+
// Start http server.
- if err := http.ListenAndServe(*httpaddr, handler); err != nil {
- log.Exitf("ListenAndServe %s: %v", *httpaddr, err)
+ if err := http.ListenAndServe(*httpAddr, handler); err != nil {
+ log.Exitf("ListenAndServe %s: %v", *httpAddr, err)
}
+
return
}
// Command line mode.
if *html {
packageText = packageHTML
+ searchText = packageHTML
+ }
+
+ if *query {
+ // Command-line queries.
+ for i := 0; i < flag.NArg(); i++ {
+ result, err := remoteLookup(flag.Arg(i))
+ if err != nil {
+ log.Exitf("remoteLookup: %s", err)
+ }
+ if err := searchText.Execute(result, os.Stdout); err != nil {
+ log.Exitf("searchText.Execute: %s", err)
+ }
+ }
+ return
}
// determine paths