├── gopresent
├── static
│ ├── favicon.ico
│ ├── print.css
│ ├── dir.js
│ ├── article.css
│ ├── dir.css
│ ├── styles.css
│ └── slides.js
├── templates
│ ├── action.tmpl
│ ├── article.tmpl
│ └── slides.tmpl
└── gopresent.go
├── doc.go
├── go.mod
├── .gitignore
├── pkg
├── stdlib
│ ├── go13.go
│ ├── go14.go
│ ├── mkstdlib.go
│ ├── mkpkglist.go
│ └── pkglist.go
├── command
│ ├── version.go
│ └── command.go
├── buildctx
│ └── context.go
├── godiff
│ └── godiff.go
├── gomod
│ └── gomod.go
├── pkgwalk
│ └── allpackages.go
├── srcimporter
│ └── srcimporter.go
└── pkgutil
│ └── pkgutil.go
├── README.md
├── terminal
├── command.go
├── command_windows.go
└── terminal.go
├── .github
└── workflows
│ └── go.yml
├── astview
├── ast_go117.go
├── ast_go118.go
└── astview.go
├── types
├── types_go117.go
├── types_go118.go
└── types_test.go
├── godoc
└── godoc.go
├── LICENSE
├── main.go
├── pkgcheck
└── check.go
├── runcmd
└── runcmd.go
├── docview
├── filesystem.go
├── docview.go
└── dirtrees.go
├── debugflags
└── debugflags.go
├── gotest
└── gotest.go
├── finddecl
└── finddecl.go
├── go.sum
├── jsonfmt
└── jsonfmt.go
├── gofmt
└── gofmt.go
├── pkgs
└── pkgs.go
└── finddoc
└── finddoc.go
/gopresent/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/visualfc/gotools/HEAD/gopresent/static/favicon.ico
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2017 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | /*
6 | gotools document
7 | */
8 | package main
9 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/visualfc/gotools
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/creack/pty v1.1.21
7 | github.com/pmezard/go-difflib v1.0.0
8 | github.com/visualfc/gomod v0.1.2
9 | github.com/visualfc/goversion v1.1.0
10 | golang.org/x/tools v0.5.0
11 | )
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 |
10 | # Architecture specific extensions/prefixes
11 | *.[568vq]
12 | [568vq].out
13 |
14 | *.cgo1.go
15 | *.cgo2.c
16 | _cgo_defun.c
17 | _cgo_gotypes.go
18 | _cgo_export.*
19 |
20 | _testmain.go
21 |
22 | *.exe
23 | *.test
24 | *.prof
25 |
--------------------------------------------------------------------------------
/pkg/stdlib/go13.go:
--------------------------------------------------------------------------------
1 | // +build !go1.4
2 |
3 | package stdlib
4 |
5 | import (
6 | "go/build"
7 | "os"
8 | "path/filepath"
9 | )
10 |
11 | func ImportStdPkg(context *build.Context, path string, mode build.ImportMode) (*build.Package, error) {
12 | realpath := filepath.Join(context.GOROOT, "src", "pkg", path)
13 | if _, err := os.Stat(realpath); err != nil {
14 | realpath = filepath.Join(context.GOROOT, "src", path)
15 | }
16 | pkg, err := context.ImportDir(realpath, 0)
17 | pkg.ImportPath = path
18 | return pkg, err
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/stdlib/go14.go:
--------------------------------------------------------------------------------
1 | // +build go1.4
2 |
3 | package stdlib
4 |
5 | import (
6 | "go/build"
7 | "os"
8 | "path/filepath"
9 | )
10 |
11 | func ImportStdPkg(context *build.Context, path string, mode build.ImportMode) (*build.Package, error) {
12 | realpath := filepath.Join(context.GOROOT, "src", path)
13 | if _, err := os.Stat(realpath); err != nil {
14 | realpath = filepath.Join(context.GOROOT, "src/pkg", path)
15 | }
16 | pkg, err := context.ImportDir(realpath, 0)
17 | pkg.ImportPath = path
18 | return pkg, err
19 | }
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LiteIDE Golang Tools
2 | =========
3 |
4 | ### LiteIDE
5 |
6 | _LiteIDE is a simple, open source, cross-platform Go IDE._
7 |
8 | ### GoTools
9 | _GoTools is a golang tools support for LiteIDE._
10 |
11 | ```
12 | go install github.com/visualfc/gotools@latest
13 |
14 | Windows/Linux: copy GOPATH/bin gotools to liteide/bin
15 | MacOS: copy GOPATH/bin gotools to LiteIDE.app/Contents/MacOS
16 | ```
17 |
18 | ### Website
19 | * LiteIDE Source code
20 |
21 | * Gotools Source code
22 |
23 |
--------------------------------------------------------------------------------
/terminal/command.go:
--------------------------------------------------------------------------------
1 | // +build !windows
2 |
3 | package terminal
4 |
5 | import (
6 | "io"
7 | "os"
8 | "os/exec"
9 |
10 | "github.com/creack/pty"
11 | )
12 |
13 | func GetShell() (cmd string, args []string) {
14 | return "/bin/sh", []string{"-l", "-i"}
15 | }
16 |
17 | func Execute(c *exec.Cmd) error {
18 | f, err := pty.Start(c)
19 | if err != nil {
20 | return nil
21 | }
22 | go func() {
23 | for {
24 | io.Copy(f, os.Stdin)
25 | }
26 | }()
27 | go func() {
28 | for {
29 | io.Copy(os.Stdout, f)
30 | }
31 | }()
32 | return c.Wait()
33 | }
34 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: gotools
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | Test:
11 | strategy:
12 | matrix:
13 | go-version: [1.16.x, 1.17.x, 1.18.x, 1.19.x]
14 | os: [ubuntu-latest, windows-latest, macos-11]
15 | runs-on: ${{ matrix.os }}
16 | steps:
17 | - uses: actions/checkout@v2
18 |
19 | - name: Set up Go
20 | uses: actions/setup-go@v2
21 | with:
22 | go-version: ${{ matrix.go-version }}
23 |
24 | - name: Test
25 | run: go test -v ./...
26 |
27 |
--------------------------------------------------------------------------------
/terminal/command_windows.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package terminal
4 |
5 | import (
6 | "os"
7 | "os/exec"
8 | )
9 |
10 | func checkFiles(names ...string) string {
11 | for _, name := range names {
12 | _, err := os.Stat(name)
13 | if err == nil {
14 | return name
15 | }
16 | }
17 | return ""
18 | }
19 |
20 | func GetShell() (cmd string, args []string) {
21 | windir := os.Getenv("windir")
22 | if windir == "" {
23 | windir = "c:\\windows"
24 | }
25 | cmd = checkFiles(windir+"\\Sysnative\\cmd.exe", windir+"\\System32\\cmd.exe")
26 | return
27 | }
28 |
29 | func Execute(c *exec.Cmd) error {
30 | c.Stdin = os.Stdin
31 | c.Stdout = os.Stdout
32 | c.Stderr = os.Stderr
33 | return c.Run()
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/command/version.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package command
6 |
7 | import (
8 | "os"
9 | "runtime"
10 | )
11 |
12 | func init() {
13 | Register(cmdVersion)
14 | }
15 |
16 | var AppVersion string = "1.0"
17 |
18 | var cmdVersion = &Command{
19 | Run: runVersion,
20 | UsageLine: "version",
21 | Short: "print tool version",
22 | Long: `Version prints the version.`,
23 | }
24 |
25 | func runVersion(cmd *Command, args []string) error {
26 | if len(args) != 0 {
27 | cmd.PrintUsage()
28 | return os.ErrInvalid
29 | }
30 |
31 | cmd.Printf("%s version %s [%s %s/%s]\n", AppName, AppVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/astview/ast_go117.go:
--------------------------------------------------------------------------------
1 | //go:build !go1.18
2 | // +build !go1.18
3 |
4 | package astview
5 |
6 | import "go/ast"
7 |
8 | func docBaseTypeName(typ ast.Expr, showAll bool) string {
9 | name, _ := recvTypeName(typ, showAll)
10 | return name
11 | }
12 |
13 | func recvTypeName(typ ast.Expr, showAll bool) (string, bool) {
14 | switch t := typ.(type) {
15 | case *ast.Ident:
16 | // if the type is not exported, the effect to
17 | // a client is as if there were no type name
18 | if showAll || t.IsExported() {
19 | return t.Name, false
20 | }
21 | case *ast.StarExpr:
22 | return docBaseTypeName(t.X, showAll), true
23 | }
24 | return "", false
25 | }
26 |
27 | func typeName(ts *ast.TypeSpec, showTypeParams bool) string {
28 | return ts.Name.String()
29 | }
30 |
31 | func funcName(d *ast.FuncDecl, showTypeParams bool) string {
32 | return d.Name.String()
33 | }
34 |
--------------------------------------------------------------------------------
/terminal/terminal.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2017 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 | package terminal
5 |
6 | import (
7 | "os"
8 | "os/exec"
9 |
10 | "github.com/visualfc/gotools/pkg/command"
11 | )
12 |
13 | var Command = &command.Command{
14 | Run: runTerminal,
15 | UsageLine: "terminal [program_name arguments...]",
16 | Short: "terminal [program]",
17 | Long: `terminal program and arguments`,
18 | CustomFlags: true,
19 | }
20 |
21 | func runTerminal(cmd *command.Command, args []string) (err error) {
22 | var c *exec.Cmd
23 | if len(args) >= 1 {
24 | var carg []string
25 | if len(args) >= 2 {
26 | carg = append(carg, args[1:]...)
27 | }
28 | c = exec.Command(args[0], carg...)
29 | } else {
30 | shellCmd, shellArgs := GetShell()
31 | c = exec.Command(shellCmd, shellArgs...)
32 | }
33 | if c == nil {
34 | return os.ErrInvalid
35 | }
36 | err = Execute(c)
37 |
38 | return
39 | }
40 |
--------------------------------------------------------------------------------
/gopresent/static/print.css:
--------------------------------------------------------------------------------
1 | /* set page layout */
2 | @page {
3 | size: A4 landscape;
4 | }
5 |
6 | body {
7 | display: block !important;
8 | }
9 |
10 | .slides {
11 | left: 0;
12 | top: 0;
13 | }
14 |
15 | .slides > article {
16 | position: relative;
17 |
18 | left: 0;
19 | top: 0;
20 |
21 | margin: 0 !important;
22 | page-break-inside: avoid;
23 |
24 | text-shadow: none; /* disable shadow */
25 |
26 | display: block !important;
27 | transform: translate(0) !important;
28 | -o-transform: translate(0) !important;
29 | -moz-transform: translate(0) !important;
30 | -webkit-transform: translate3d(0, 0, 0) !important;
31 | }
32 |
33 | div.code {
34 | background: rgb(240, 240, 240);
35 | }
36 |
37 | /* hide click areas */
38 | .slide-area, #prev-slide-area, #next-slide-area {
39 | display: none;
40 | }
41 |
42 | /* add explicit links */
43 | a:link:after, a:visited:after {
44 | content: " (" attr(href) ") ";
45 | font-size: 50%;
46 | }
47 |
48 | /* white background */
49 | body {
50 | background: rgb(255,255,255) !important;
51 | }
52 |
--------------------------------------------------------------------------------
/types/types_go117.go:
--------------------------------------------------------------------------------
1 | //go:build !go1.18
2 | // +build !go1.18
3 |
4 | package types
5 |
6 | import (
7 | "go/ast"
8 | "go/types"
9 | )
10 |
11 | const enableTypeParams = false
12 |
13 | func DefaultPkgConfig() *PkgConfig {
14 | conf := &PkgConfig{IgnoreFuncBodies: false, AllowBinary: true, WithTestFiles: true}
15 | conf.Info = &types.Info{
16 | Uses: make(map[*ast.Ident]types.Object),
17 | Defs: make(map[*ast.Ident]types.Object),
18 | Selections: make(map[*ast.SelectorExpr]*types.Selection),
19 | Types: make(map[ast.Expr]types.TypeAndValue),
20 | Scopes: make(map[ast.Node]*types.Scope),
21 | Implicits: make(map[ast.Node]types.Object),
22 | }
23 | conf.XInfo = &types.Info{
24 | Uses: make(map[*ast.Ident]types.Object),
25 | Defs: make(map[*ast.Ident]types.Object),
26 | Selections: make(map[*ast.SelectorExpr]*types.Selection),
27 | Types: make(map[ast.Expr]types.TypeAndValue),
28 | Scopes: make(map[ast.Node]*types.Scope),
29 | Implicits: make(map[ast.Node]types.Object),
30 | }
31 | return conf
32 | }
33 |
34 | func sameNamed(n1, n2 *types.Named) bool {
35 | return n1 == n2
36 | }
37 |
--------------------------------------------------------------------------------
/pkg/buildctx/context.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2018 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package buildctx
6 |
7 | import (
8 | "go/build"
9 | "os"
10 | )
11 |
12 | var (
13 | fnLookupEnv = os.LookupEnv
14 | )
15 |
16 | func SetLookupEnv(fn func(key string) (string, bool)) {
17 | if fn != nil {
18 | fnLookupEnv = fn
19 | } else {
20 | fnLookupEnv = os.LookupEnv
21 | }
22 | }
23 |
24 | func Default() *build.Context {
25 | return &build.Default
26 | }
27 |
28 | func System() *build.Context {
29 | return NewContext(fnLookupEnv)
30 | }
31 |
32 | func NewContext(env func(key string) (string, bool)) *build.Context {
33 | c := build.Default
34 | if v, ok := env("GOARCH"); ok {
35 | c.GOARCH = v
36 | }
37 | if v, ok := env("GOOS"); ok {
38 | c.GOOS = v
39 | }
40 | if v, ok := env("GOROOT"); ok {
41 | c.GOROOT = v
42 | }
43 | if v, ok := env("GOPATH"); ok {
44 | c.GOPATH = v
45 | }
46 | if v, ok := env("CGO_ENABLED"); ok {
47 | switch v {
48 | case "1":
49 | c.CgoEnabled = true
50 | case "0":
51 | c.CgoEnabled = false
52 | }
53 | }
54 | return &c
55 | }
56 |
--------------------------------------------------------------------------------
/gopresent/static/dir.js:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // copied from $GOROOT/doc/godocs.js
6 |
7 | function bindEvent(el, e, fn) {
8 | if (el.addEventListener){
9 | el.addEventListener(e, fn, false);
10 | } else if (el.attachEvent){
11 | el.attachEvent('on'+e, fn);
12 | }
13 | }
14 |
15 | function godocs_bindSearchEvents() {
16 | var search = document.getElementById('search');
17 | if (!search) {
18 | // no search box (index disabled)
19 | return;
20 | }
21 | function clearInactive() {
22 | if (search.className == "inactive") {
23 | search.value = "";
24 | search.className = "";
25 | }
26 | }
27 | function restoreInactive() {
28 | if (search.value !== "") {
29 | return;
30 | }
31 | if (search.type != "search") {
32 | search.value = search.getAttribute("placeholder");
33 | }
34 | search.className = "inactive";
35 | }
36 | restoreInactive();
37 | bindEvent(search, 'focus', clearInactive);
38 | bindEvent(search, 'blur', restoreInactive);
39 | }
40 |
41 | bindEvent(window, 'load', godocs_bindSearchEvents);
42 |
--------------------------------------------------------------------------------
/types/types_go118.go:
--------------------------------------------------------------------------------
1 | //go:build go1.18
2 | // +build go1.18
3 |
4 | package types
5 |
6 | import (
7 | "go/ast"
8 | "go/types"
9 | )
10 |
11 | const enableTypeParams = true
12 |
13 | func DefaultPkgConfig() *PkgConfig {
14 | conf := &PkgConfig{IgnoreFuncBodies: false, AllowBinary: true, WithTestFiles: true}
15 | conf.Info = &types.Info{
16 | Uses: make(map[*ast.Ident]types.Object),
17 | Defs: make(map[*ast.Ident]types.Object),
18 | Selections: make(map[*ast.SelectorExpr]*types.Selection),
19 | Types: make(map[ast.Expr]types.TypeAndValue),
20 | Scopes: make(map[ast.Node]*types.Scope),
21 | Implicits: make(map[ast.Node]types.Object),
22 | Instances: make(map[*ast.Ident]types.Instance),
23 | }
24 | conf.XInfo = &types.Info{
25 | Uses: make(map[*ast.Ident]types.Object),
26 | Defs: make(map[*ast.Ident]types.Object),
27 | Selections: make(map[*ast.SelectorExpr]*types.Selection),
28 | Types: make(map[ast.Expr]types.TypeAndValue),
29 | Scopes: make(map[ast.Node]*types.Scope),
30 | Implicits: make(map[ast.Node]types.Object),
31 | Instances: make(map[*ast.Ident]types.Instance),
32 | }
33 | return conf
34 | }
35 |
36 | func sameNamed(n1, n2 *types.Named) bool {
37 | return n1 != nil && n2 != nil && n1.Origin().String() == n2.Origin().String()
38 | }
39 |
--------------------------------------------------------------------------------
/gopresent/templates/action.tmpl:
--------------------------------------------------------------------------------
1 | {/*
2 | This is the action template.
3 | It determines how the formatting actions are rendered.
4 | */}
5 |
6 | {{define "section"}}
7 | {{.FormattedNumber}} {{.Title}}
8 | {{range .Elem}}{{elem $.Template .}}{{end}}
9 | {{end}}
10 |
11 | {{define "list"}}
12 |
13 | {{range .Bullet}}
14 | {{style .}}
15 | {{end}}
16 |
17 | {{end}}
18 |
19 | {{define "text"}}
20 | {{if .Pre}}
21 | {{range .Lines}}{{.}}{{end}}
22 | {{else}}
23 |
24 | {{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}
25 | {{end}}{{style $l}}{{end}}
26 |
27 | {{end}}
28 | {{end}}
29 |
30 | {{define "code"}}
31 | {{.Text}}
32 | {{end}}
33 |
34 | {{define "image"}}
35 |
36 |
37 |
38 | {{end}}
39 |
40 | {{define "iframe"}}
41 |
42 | {{end}}
43 |
44 | {{define "link"}}{{style .Label}}
{{end}}
45 |
46 | {{define "html"}}{{.HTML}}{{end}}
47 |
--------------------------------------------------------------------------------
/godoc/godoc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2018 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package godoc
6 |
7 | import (
8 | "errors"
9 | "os/exec"
10 |
11 | "github.com/visualfc/gotools/pkg/command"
12 | "github.com/visualfc/goversion"
13 | )
14 |
15 | var Command = &command.Command{
16 | Run: runDoc,
17 | UsageLine: "godoc [pkg]",
18 | Short: "golang doc print",
19 | Long: "golang document print",
20 | }
21 |
22 | var (
23 | GoVer112 = goversion.GoVersion{1, 12, -1, 0, 0, ""}
24 | )
25 |
26 | func runDoc(cmd *command.Command, args []string) error {
27 | if len(args) < 1 {
28 | return nil
29 | }
30 | ver, _, ok := goversion.Installed()
31 | if !ok {
32 | return errors.New("could not parse output of go version")
33 | }
34 | gocmd, err := exec.LookPath("go")
35 | if err != nil {
36 | return err
37 | }
38 | var godoc_html bool
39 | godoc, err := exec.LookPath("godoc")
40 | if err == nil {
41 | godoc_html = true
42 | }
43 | if ver.AfterOrEqual(GoVer112) {
44 | godoc_html = false
45 | }
46 | var command *exec.Cmd
47 | if godoc_html {
48 | command = exec.Command(godoc, "-html", args[0])
49 | } else {
50 | command = exec.Command(gocmd, "doc", "-all", args[0])
51 | }
52 | command.Stdin = cmd.Stdin
53 | command.Stdout = cmd.Stdout
54 | command.Stderr = cmd.Stderr
55 | return command.Run()
56 | }
57 |
--------------------------------------------------------------------------------
/gopresent/templates/article.tmpl:
--------------------------------------------------------------------------------
1 | {/* This is the article template. It defines how articles are formatted. */}
2 |
3 | {{define "root"}}
4 |
5 |
6 |
7 | {{.Title}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
{{.Title}}
16 | {{with .Subtitle}}{{.}}{{end}}
17 |
18 |
19 |
20 |
21 |
22 | {{with .Sections}}
23 |
24 | {{template "TOC" .}}
25 |
26 | {{end}}
27 |
28 | {{range .Sections}}
29 | {{elem $.Template .}}
30 | {{end}}{{/* of Section block */}}
31 |
32 |
Authors
33 | {{range .Authors}}
34 |
35 | {{range .Elem}}{{elem $.Template .}}{{end}}
36 |
37 | {{end}}
38 |
39 |
40 |
41 |
42 |
43 | {{end}}
44 |
45 | {{define "TOC"}}
46 |
47 | {{range .}}
48 | {{.Title}}
49 | {{with .Sections}}{{template "TOC" .}}{{end}}
50 | {{end}}
51 |
52 | {{end}}
53 |
54 | {{define "newline"}}
55 | {{/* No automatic line break. Paragraphs are free-form. */}}
56 | {{end}}
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2017, visualfc
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of gotools nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/gopresent/templates/slides.tmpl:
--------------------------------------------------------------------------------
1 | {/* This is the slide template. It defines how presentations are formatted. */}
2 |
3 | {{define "root"}}
4 |
5 |
6 |
7 | {{.Title}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{.Title}}
18 | {{with .Subtitle}}{{.}} {{end}}
19 | {{if not .Time.IsZero}}{{.Time.Format "2 January 2006"}} {{end}}
20 | {{range .Authors}}
21 |
22 | {{range .TextElem}}{{elem $.Template .}}{{end}}
23 |
24 | {{end}}
25 |
26 |
27 | {{range $i, $s := .Sections}}
28 |
29 |
30 | {{if $s.Elem}}
31 | {{$s.Title}}
32 | {{range $s.Elem}}{{elem $.Template .}}{{end}}
33 | {{else}}
34 | {{$s.Title}}
35 | {{end}}
36 |
37 |
38 | {{end}}{{/* of Slide block */}}
39 |
40 |
41 | Thank you
42 | {{range .Authors}}
43 |
44 | {{range .Elem}}{{elem $.Template .}}{{end}}
45 |
46 | {{end}}
47 |
48 |
49 |
50 | {{if .PlayEnabled}}
51 |
52 | {{end}}
53 |
54 | {{end}}
55 |
56 | {{define "newline"}}
57 |
58 | {{end}}
59 |
--------------------------------------------------------------------------------
/pkg/godiff/godiff.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package godiff
6 |
7 | import (
8 | "io/ioutil"
9 | "os"
10 | "os/exec"
11 |
12 | "github.com/pmezard/go-difflib/difflib"
13 | )
14 |
15 | func UnifiedDiffLines(a []string, b []string) (string, error) {
16 | diff := difflib.UnifiedDiff{
17 | A: a,
18 | B: b,
19 | FromFile: "Original",
20 | ToFile: "Current",
21 | Context: 3,
22 | Eol: "\n",
23 | }
24 | return difflib.GetUnifiedDiffString(diff)
25 | }
26 |
27 | func UnifiedDiffString(a string, b string) (string, error) {
28 | diff := difflib.UnifiedDiff{
29 | A: difflib.SplitLines(a),
30 | B: difflib.SplitLines(b),
31 | FromFile: "Original",
32 | ToFile: "Current",
33 | Context: 3,
34 | Eol: "\n",
35 | }
36 | return difflib.GetUnifiedDiffString(diff)
37 | }
38 |
39 | func UnifiedDiffBytesByCmd(b1, b2 []byte) (data []byte, err error) {
40 | f1, err := ioutil.TempFile("", "godiff")
41 | if err != nil {
42 | return
43 | }
44 | defer os.Remove(f1.Name())
45 | defer f1.Close()
46 |
47 | f2, err := ioutil.TempFile("", "godiff")
48 | if err != nil {
49 | return
50 | }
51 | defer os.Remove(f2.Name())
52 | defer f2.Close()
53 |
54 | f1.Write(b1)
55 | f2.Write(b2)
56 |
57 | data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
58 | if len(data) > 0 {
59 | // diff exits with a non-zero status when the files don't match.
60 | // Ignore that failure as long as we get output.
61 | err = nil
62 | }
63 | return
64 | }
65 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2023 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package main
6 |
7 | import (
8 | "github.com/visualfc/gotools/astview"
9 | "github.com/visualfc/gotools/debugflags"
10 | "github.com/visualfc/gotools/docview"
11 | "github.com/visualfc/gotools/finddecl"
12 | "github.com/visualfc/gotools/finddoc"
13 | "github.com/visualfc/gotools/goapi"
14 | "github.com/visualfc/gotools/godoc"
15 | "github.com/visualfc/gotools/gofmt"
16 | "github.com/visualfc/gotools/gopresent"
17 | "github.com/visualfc/gotools/gotest"
18 | "github.com/visualfc/gotools/jsonfmt"
19 | "github.com/visualfc/gotools/pkg/command"
20 | "github.com/visualfc/gotools/pkgcheck"
21 | "github.com/visualfc/gotools/pkgs"
22 | "github.com/visualfc/gotools/runcmd"
23 | "github.com/visualfc/gotools/terminal"
24 | "github.com/visualfc/gotools/types"
25 | )
26 |
27 | func init() {
28 | command.Register(types.Command)
29 | command.Register(jsonfmt.Command)
30 | command.Register(finddoc.Command)
31 | command.Register(runcmd.Command)
32 | command.Register(docview.Command)
33 | command.Register(astview.Command)
34 | command.Register(gopresent.Command)
35 | command.Register(goapi.Command)
36 | command.Register(pkgs.Command)
37 | command.Register(gofmt.Command)
38 | command.Register(gotest.Command)
39 | command.Register(finddecl.Command)
40 | command.Register(terminal.Command)
41 | command.Register(debugflags.Command)
42 | command.Register(pkgcheck.Command)
43 | command.Register(godoc.Command)
44 | }
45 |
46 | func main() {
47 | command.AppName = "gotools"
48 | command.AppVersion = "1.4"
49 | command.AppInfo = "Go tools for liteide."
50 | command.Main()
51 | }
52 |
--------------------------------------------------------------------------------
/types/types_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "go/build"
6 | "os"
7 | "testing"
8 | )
9 |
10 | func TestTypes(t *testing.T) {
11 | w := NewPkgWalker(&build.Default)
12 | w.SetOutput(os.Stdout, os.Stderr)
13 | w.SetFindMode(&FindMode{Info: true, Doc: true, Define: true})
14 | conf := DefaultPkgConfig()
15 | dir, _ := os.Getwd()
16 | cursor := NewFileCursor(nil, dir, "types_test.go", 126)
17 | pkg, conf, err := w.Check(dir, conf, cursor)
18 | if err != nil {
19 | t.Fatalf("error %v\n", err)
20 | }
21 | w.LookupCursor(pkg, conf, cursor)
22 | }
23 |
24 | func test_error() {
25 | e := fmt.Errorf("error_test")
26 | _ = e.Error()
27 | }
28 |
29 | func TestError(t *testing.T) {
30 | w := NewPkgWalker(&build.Default)
31 | w.SetOutput(os.Stdout, os.Stderr)
32 | w.SetFindMode(&FindMode{Info: true, Doc: true, Define: true, Usage: true, UsageAll: true})
33 | conf := DefaultPkgConfig()
34 | dir, _ := os.Getwd()
35 | cursor := NewFileCursor(nil, dir, "types_test.go", 530)
36 | pkg, conf, err := w.Check(dir, conf, cursor)
37 | if err != nil {
38 | t.Fatalf("error %v\n", err)
39 | }
40 | w.LookupCursor(pkg, conf, cursor)
41 | }
42 |
43 | func TestOS(t *testing.T) {
44 | w := NewPkgWalker(&build.Default)
45 |
46 | w.SetOutput(os.Stdout, os.Stderr)
47 | w.SetFindMode(&FindMode{Info: true, Doc: true, Define: true})
48 | conf := DefaultPkgConfig()
49 | fn1 := func() {
50 | cursor := NewFileCursor(nil, "", "dir_windows.go", 235)
51 | pkg, conf, _ := w.Check("os", conf, cursor)
52 | w.LookupCursor(pkg, conf, cursor)
53 | }
54 | fn2 := func() {
55 | cursor := NewFileCursor(nil, "", "dir_unix.go", 1040)
56 | pkg, conf, _ := w.Check("os", conf, cursor)
57 | w.LookupCursor(pkg, conf, cursor)
58 | }
59 | for i := 0; i < 2; i++ {
60 | fn1()
61 | fn2()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/astview/ast_go118.go:
--------------------------------------------------------------------------------
1 | //go:build go1.18
2 | // +build go1.18
3 |
4 | package astview
5 |
6 | import (
7 | "go/ast"
8 | "go/types"
9 | "strings"
10 | )
11 |
12 | func docBaseTypeName(typ ast.Expr, showAll bool) string {
13 | name, _ := recvTypeName(typ, showAll)
14 | return name
15 | }
16 |
17 | func recvTypeName(typ ast.Expr, showAll bool) (string, bool) {
18 | switch t := typ.(type) {
19 | case *ast.Ident:
20 | // if the type is not exported, the effect to
21 | // a client is as if there were no type name
22 | if showAll || t.IsExported() {
23 | return t.Name, false
24 | }
25 | case *ast.StarExpr:
26 | return docBaseTypeName(t.X, showAll), true
27 | case *ast.IndexExpr:
28 | return docBaseTypeName(t.X, showAll), false
29 | case *ast.IndexListExpr:
30 | return docBaseTypeName(t.X, showAll), false
31 | }
32 | return "", false
33 | }
34 |
35 | func typeName(d *ast.TypeSpec, showTypeParams bool) string {
36 | if showTypeParams && d.TypeParams != nil {
37 | tparams := d.TypeParams
38 | var fs []string
39 | n := len(tparams.List)
40 | for i := 0; i < n; i++ {
41 | f := tparams.List[i]
42 | for _, name := range f.Names {
43 | fs = append(fs, name.String()+" "+types.ExprString(f.Type))
44 | }
45 | }
46 | return d.Name.String() + "[" + strings.Join(fs, ", ") + "]"
47 | }
48 | return d.Name.String()
49 | }
50 |
51 | func funcName(d *ast.FuncDecl, showTypeParams bool) string {
52 | if showTypeParams && d.Type.TypeParams != nil {
53 | tparams := d.Type.TypeParams
54 | var fs []string
55 | n := len(tparams.List)
56 | for i := 0; i < n; i++ {
57 | f := tparams.List[i]
58 | for _, name := range f.Names {
59 | fs = append(fs, name.String()+" "+types.ExprString(f.Type))
60 | }
61 | }
62 | return d.Name.String() + "[" + strings.Join(fs, ", ") + "]"
63 | }
64 | return d.Name.String()
65 | }
66 |
--------------------------------------------------------------------------------
/pkgcheck/check.go:
--------------------------------------------------------------------------------
1 | package pkgcheck
2 |
3 | import (
4 | "fmt"
5 | "go/build"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/visualfc/gomod"
10 | "github.com/visualfc/gotools/pkg/command"
11 | "github.com/visualfc/gotools/pkg/pkgutil"
12 | )
13 |
14 | var Command = &command.Command{
15 | Run: runCheck,
16 | UsageLine: "pkgcheck [-pkg | -name] -w .",
17 | Short: "pkg check utils",
18 | Long: "check pkg mod or vendor path",
19 | }
20 |
21 | var (
22 | flagCheckPkg string
23 | flagCheckDir string = "."
24 | flagCheckName bool
25 | )
26 |
27 | func init() {
28 | Command.Flag.StringVar(&flagCheckPkg, "pkg", "", "check pkg name")
29 | Command.Flag.BoolVar(&flagCheckName, "name", false, "check module name")
30 | Command.Flag.StringVar(&flagCheckDir, "w", "", "work path")
31 | }
32 |
33 | func runCheck(cmd *command.Command, args []string) error {
34 | if flagCheckPkg == "" && !flagCheckName {
35 | cmd.Usage()
36 | return os.ErrInvalid
37 | }
38 | if flagCheckDir == "" || flagCheckDir == "." {
39 | flagCheckDir, _ = os.Getwd()
40 | }
41 | mod, _ := gomod.Load(flagCheckDir, &build.Default)
42 | if flagCheckName {
43 | if mod != nil {
44 | fmt.Println(mod.Root().Path)
45 | } else {
46 | _, fname := filepath.Split(flagCheckDir)
47 | fmt.Println(fname)
48 | }
49 | return nil
50 | }
51 | // check mod, check vendor
52 | if mod != nil {
53 | _, dir, _ := mod.Lookup(flagCheckPkg)
54 | if dir != "" {
55 | fmt.Printf("%s,mod\n", dir)
56 | return nil
57 | }
58 | } else {
59 | pkg := pkgutil.ImportDir(flagCheckDir)
60 | if pkg != nil {
61 | found, _ := pkgutil.VendoredImportPath(pkg, flagCheckPkg)
62 | if found != "" && found != flagCheckPkg {
63 | fmt.Printf("%s,vendor\n", found)
64 | return nil
65 | }
66 | }
67 | }
68 | fmt.Printf("%s,pkg\n", flagCheckPkg)
69 | return nil
70 | }
71 |
--------------------------------------------------------------------------------
/runcmd/runcmd.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package runcmd
6 |
7 | import (
8 | "fmt"
9 | "os"
10 | "os/exec"
11 | "strings"
12 |
13 | "github.com/visualfc/gotools/pkg/command"
14 | )
15 |
16 | var Command = &command.Command{
17 | Run: runCmd,
18 | UsageLine: "runcmd [-w work_path] [arguments...]",
19 | Short: "run program",
20 | Long: `run program and arguments`,
21 | }
22 |
23 | var execWorkPath string
24 | var execWaitEnter bool
25 |
26 | func init() {
27 | Command.Flag.StringVar(&execWorkPath, "w", "", "work path")
28 | Command.Flag.BoolVar(&execWaitEnter, "e", true, "wait enter and continue")
29 | }
30 |
31 | func runCmd(cmd *command.Command, args []string) error {
32 | if len(args) == 0 {
33 | cmd.Usage()
34 | return os.ErrInvalid
35 | }
36 | if execWorkPath == "" {
37 | var err error
38 | execWorkPath, err = os.Getwd()
39 | if err != nil {
40 | return err
41 | }
42 | }
43 | fileName := args[0]
44 |
45 | filePath, err := exec.LookPath(fileName)
46 | if err != nil {
47 | filePath, err = exec.LookPath("./" + fileName)
48 | }
49 | if err != nil {
50 | return err
51 | }
52 |
53 | fmt.Println("Starting Process", filePath, strings.Join(args[1:], " "), "...")
54 |
55 | command := exec.Command(filePath, args[1:]...)
56 | command.Dir = execWorkPath
57 | command.Stdin = os.Stdin
58 | command.Stdout = os.Stdout
59 | command.Stderr = os.Stderr
60 |
61 | err = command.Run()
62 |
63 | if err != nil {
64 | fmt.Println("\nEnd Process", err)
65 | } else {
66 | fmt.Println("\nEnd Process", "exit status 0")
67 | }
68 |
69 | exitWaitEnter()
70 | return nil
71 | }
72 |
73 | func exitWaitEnter() {
74 | if !execWaitEnter {
75 | return
76 | }
77 | fmt.Println("\nPress enter key to continue")
78 | var s = [256]byte{}
79 | os.Stdin.Read(s[:])
80 | }
81 |
--------------------------------------------------------------------------------
/docview/filesystem.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // This file defines types for abstract file system access and
6 | // provides an implementation accessing the file system of the
7 | // underlying OS.
8 |
9 | package docview
10 |
11 | import (
12 | "fmt"
13 | "io"
14 | "io/ioutil"
15 | "os"
16 | )
17 |
18 | // The FileSystem interface specifies the methods godoc is using
19 | // to access the file system for which it serves documentation.
20 | type FileSystem interface {
21 | Open(path string) (io.ReadCloser, error)
22 | Lstat(path string) (os.FileInfo, error)
23 | Stat(path string) (os.FileInfo, error)
24 | ReadDir(path string) ([]os.FileInfo, error)
25 | }
26 |
27 | // ReadFile reads the file named by path from fs and returns the contents.
28 | func ReadFile(fs FileSystem, path string) ([]byte, error) {
29 | rc, err := fs.Open(path)
30 | if err != nil {
31 | return nil, err
32 | }
33 | defer rc.Close()
34 | return ioutil.ReadAll(rc)
35 | }
36 |
37 | // ----------------------------------------------------------------------------
38 | // OS-specific FileSystem implementation
39 |
40 | var OS FileSystem = osFS{}
41 |
42 | // osFS is the OS-specific implementation of FileSystem
43 | type osFS struct{}
44 |
45 | func (osFS) Open(path string) (io.ReadCloser, error) {
46 | f, err := os.Open(path)
47 | if err != nil {
48 | return nil, err
49 | }
50 | fi, err := f.Stat()
51 | if err != nil {
52 | return nil, err
53 | }
54 | if fi.IsDir() {
55 | return nil, fmt.Errorf("Open: %s is a directory", path)
56 | }
57 | return f, nil
58 | }
59 |
60 | func (osFS) Lstat(path string) (os.FileInfo, error) {
61 | return os.Lstat(path)
62 | }
63 |
64 | func (osFS) Stat(path string) (os.FileInfo, error) {
65 | return os.Stat(path)
66 | }
67 |
68 | func (osFS) ReadDir(path string) ([]os.FileInfo, error) {
69 | return ioutil.ReadDir(path) // is sorted
70 | }
71 |
--------------------------------------------------------------------------------
/debugflags/debugflags.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2018 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package debugflags
6 |
7 | import (
8 | "errors"
9 | "runtime"
10 |
11 | "github.com/visualfc/gotools/pkg/command"
12 | "github.com/visualfc/goversion"
13 | )
14 |
15 | var Command = &command.Command{
16 | Run: runDebugFlags,
17 | UsageLine: "debugflags",
18 | Short: "print go debug flags",
19 | Long: `print go debug flags`,
20 | CustomFlags: true,
21 | }
22 |
23 | func runDebugFlags(cmd *command.Command, args []string) error {
24 | var buildFlagsDefault string
25 | if runtime.GOOS == "windows" {
26 | ver, _, ok := goversion.Installed()
27 | if !ok {
28 | return errors.New("could not parse output of go version")
29 | }
30 | if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) {
31 | // Work-around for https://github.com/golang/go/issues/13154
32 | buildFlagsDefault = "-ldflags='-linkmode internal'"
33 | }
34 | }
35 | flags := debugflags()
36 | if buildFlagsDefault != "" {
37 | flags += " " + buildFlagsDefault
38 | }
39 | cmd.Println(flags)
40 | return nil
41 | }
42 |
43 | // copy from github.com/derekparker/delve/cmd/dlv/cmds/commands.go
44 | func debugflags() string {
45 | // after go1.9 building with -gcflags='-N -l' and -a simultaneously works.
46 | // after go1.10 specifying -a is unnecessary because of the new caching strategy, but we should pass -gcflags=all=-N -l to have it applied to all packages
47 | // see https://github.com/golang/go/commit/5993251c015dfa1e905bdf44bdb41572387edf90
48 |
49 | var flags string
50 | ver, _, ok := goversion.Installed()
51 | switch {
52 | case !ok:
53 | flags = ""
54 | case ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}):
55 | flags = "-gcflags=\"all=-N -l\""
56 | case ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}):
57 | flags = "-gcflags=\"-N -l\" -a"
58 | default:
59 | flags = "-gcflags=\"-N -l\" -a"
60 | }
61 | return flags
62 | }
63 |
--------------------------------------------------------------------------------
/gopresent/static/article.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: Helvetica, Arial, sans-serif;
4 | font-size: 16px;
5 | }
6 | pre,
7 | code {
8 | font-family: Menlo, monospace;
9 | font-size: 14px;
10 | }
11 | pre {
12 | line-height: 18px;
13 | margin: 0;
14 | padding: 0;
15 | }
16 | a {
17 | color: #375EAB;
18 | text-decoration: none;
19 | }
20 | a:hover {
21 | text-decoration: underline;
22 | }
23 | p, ul, ol {
24 | margin: 20px;
25 | }
26 |
27 | h1, h2, h3, h4 {
28 | margin: 20px 0;
29 | padding: 0;
30 | color: #375EAB;
31 | font-weight: bold;
32 | }
33 | h1 {
34 | font-size: 24px;
35 | }
36 | h2 {
37 | font-size: 20px;
38 | background: #E0EBF5;
39 | padding: 2px 5px;
40 | }
41 | h3 {
42 | font-size: 20px;
43 | }
44 | h3, h4 {
45 | margin: 20px 5px;
46 | }
47 | h4 {
48 | font-size: 16px;
49 | }
50 |
51 | div#heading {
52 | float: left;
53 | margin: 0 0 10px 0;
54 | padding: 21px 0;
55 | font-size: 20px;
56 | font-weight: normal;
57 | }
58 |
59 | div#topbar {
60 | background: #E0EBF5;
61 | height: 64px;
62 | overflow: hidden;
63 | }
64 |
65 | body {
66 | text-align: center;
67 | }
68 | div#page {
69 | width: 100%;
70 | }
71 | div#page > .container,
72 | div#topbar > .container {
73 | text-align: left;
74 | margin-left: auto;
75 | margin-right: auto;
76 | padding: 0 20px;
77 | width: 900px;
78 | }
79 | div#page.wide > .container,
80 | div#topbar.wide > .container {
81 | width: auto;
82 | }
83 |
84 | div#footer {
85 | text-align: center;
86 | color: #666;
87 | font-size: 14px;
88 | margin: 40px 0;
89 | }
90 |
91 | .author p {
92 | margin: 20, 0, 0, 0px;
93 | }
94 |
95 | div.code,
96 | div.output {
97 | margin: 20px;
98 | padding: 10px;
99 | -webkit-border-radius: 5px;
100 | -moz-border-radius: 5px;
101 | border-radius: 5px;
102 | }
103 |
104 | div.code { background: #e9e9e9; }
105 | div.output { background: black; }
106 | div.output .stdout { color: #e6e6e6; }
107 | div.output .stderr { color: rgb(244, 74, 63); }
108 | div.output .system { color: rgb(255, 209, 77) }
109 |
110 | .buttons {
111 | margin-left: 20px;
112 | }
113 | div.output .buttons {
114 | margin-left: 0;
115 | margin-bottom: 10px;
116 | }
117 |
118 | #toc {
119 | float: right;
120 | margin: 0px 10px;
121 | padding: 10px;
122 | border: 1px solid #e5ecf9;
123 | background-color: white;
124 | max-width: 33%;
125 |
126 | -webkit-border-radius: 5px;
127 | -moz-border-radius: 5px;
128 | border-radius: 5px;
129 | }
130 |
131 | #toc ul, #toc a {
132 | list-style-type: none;
133 | padding-left: 10px;
134 | color: black;
135 | margin: 0px;
136 | }
137 |
--------------------------------------------------------------------------------
/pkg/stdlib/mkstdlib.go:
--------------------------------------------------------------------------------
1 | //go:build ignore
2 | // +build ignore
3 |
4 | // mkstdlib generates the zstdlib.go file, containing the Go standard
5 | // library API symbols. It's baked into the binary to avoid scanning
6 | // GOPATH in the common case.
7 | package main
8 |
9 | import (
10 | "bufio"
11 | "bytes"
12 | "fmt"
13 | "go/format"
14 | "io"
15 | "io/ioutil"
16 | "log"
17 | "os"
18 | "path"
19 | "path/filepath"
20 | "regexp"
21 | "sort"
22 | "strings"
23 | )
24 |
25 | func mustOpen(name string) io.Reader {
26 | f, err := os.Open(name)
27 | if err != nil {
28 | log.Println(err)
29 | return nil
30 | }
31 | return f
32 | }
33 |
34 | func api(base string) string {
35 | return filepath.Join(os.Getenv("GOROOT"), "api", base)
36 | }
37 |
38 | var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`)
39 |
40 | func main() {
41 | var buf bytes.Buffer
42 | outf := func(format string, args ...interface{}) {
43 | fmt.Fprintf(&buf, format, args...)
44 | }
45 | outf("// AUTO-GENERATED BY mkstdlib.go\n\n")
46 | outf("package stdlib\n")
47 | outf("var Symbols = map[string]string{\n")
48 | f := io.MultiReader(
49 | mustOpen(api("go1.txt")),
50 | mustOpen(api("go1.1.txt")),
51 | mustOpen(api("go1.2.txt")),
52 | mustOpen(api("go1.3.txt")),
53 | mustOpen(api("go1.4.txt")),
54 | mustOpen(api("go1.5.txt")),
55 | mustOpen(api("go1.6.txt")),
56 | mustOpen(api("go1.7.txt")),
57 | mustOpen(api("go1.8.txt")),
58 | mustOpen(api("go1.9.txt")),
59 | mustOpen(api("go1.10.txt")),
60 | mustOpen(api("go1.11.txt")),
61 | mustOpen(api("go1.12.txt")),
62 | mustOpen(api("go1.13.txt")),
63 | mustOpen(api("go1.14.txt")),
64 | mustOpen(api("go1.15.txt")),
65 | mustOpen(api("go1.16.txt")),
66 | mustOpen(api("go1.17.txt")),
67 | mustOpen(api("go1.18.txt")),
68 | mustOpen(api("go1.19.txt")),
69 | mustOpen(api("go1.20.txt")),
70 | )
71 | sc := bufio.NewScanner(f)
72 | fullImport := map[string]string{} // "zip.NewReader" => "archive/zip"
73 | ambiguous := map[string]bool{}
74 | var keys []string
75 | for sc.Scan() {
76 | l := sc.Text()
77 | has := func(v string) bool { return strings.Contains(l, v) }
78 | if has("struct, ") || has("interface, ") || has(", method (") {
79 | continue
80 | }
81 | if m := sym.FindStringSubmatch(l); m != nil {
82 | full := m[1]
83 | key := path.Base(full) + "." + m[2]
84 | if exist, ok := fullImport[key]; ok {
85 | if exist != full {
86 | ambiguous[key] = true
87 | }
88 | } else {
89 | fullImport[key] = full
90 | keys = append(keys, key)
91 | }
92 | }
93 | }
94 | if err := sc.Err(); err != nil {
95 | log.Fatal(err)
96 | }
97 | sort.Strings(keys)
98 | for _, key := range keys {
99 | if ambiguous[key] {
100 | outf("\t// %q is ambiguous\n", key)
101 | } else {
102 | outf("\t%q: %q,\n", key, fullImport[key])
103 | }
104 | }
105 | outf("}\n")
106 | fmtbuf, err := format.Source(buf.Bytes())
107 | if err != nil {
108 | log.Fatal(err)
109 | }
110 | //os.Stdout.Write(fmtbuf)
111 | ioutil.WriteFile("./zstdlib.go", fmtbuf, 0777)
112 | }
113 |
--------------------------------------------------------------------------------
/gotest/gotest.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gotest
6 |
7 | import (
8 | "fmt"
9 | "go/ast"
10 | "go/build"
11 | "go/parser"
12 | "go/token"
13 | "os"
14 | "os/exec"
15 | "path/filepath"
16 | "strings"
17 |
18 | "github.com/visualfc/gotools/pkg/command"
19 | "golang.org/x/tools/go/buildutil"
20 | )
21 |
22 | var Command = &command.Command{
23 | Run: runGotest,
24 | UsageLine: "gotest -f filename [build/test flags]",
25 | Short: "go test go filename",
26 | Long: `go test go filename`,
27 | CustomFlags: true,
28 | }
29 |
30 | var testFileName string
31 | var testFileArgs string
32 |
33 | func init() {
34 | //Command.Flag.StringVar(&testFileName, "f", "", "test go filename")
35 | ApplyBuildTags()
36 | }
37 |
38 | func runGotest(cmd *command.Command, args []string) error {
39 | index := -1
40 | for n, arg := range args {
41 | if arg == "-f" {
42 | index = n
43 | break
44 | }
45 | }
46 | if index >= 0 && index < len(args) {
47 | testFileName = args[index+1]
48 | var r []string
49 | r = append(r, args[0:index]...)
50 | r = append(r, args[index+2:]...)
51 | args = r
52 | }
53 |
54 | if testFileName == "" {
55 | cmd.Usage()
56 | return os.ErrInvalid
57 | }
58 | if !strings.HasSuffix(testFileName, "_test.go") {
59 | fmt.Println("The test filename must xxx_test.go")
60 | return os.ErrInvalid
61 | }
62 | fset := token.NewFileSet()
63 | f, err := parser.ParseFile(fset, testFileName, nil, parser.ParseComments)
64 | if err != nil {
65 | return err
66 | }
67 | var fnList []string
68 | for _, decl := range f.Decls {
69 | if fn, ok := decl.(*ast.FuncDecl); ok {
70 | name := fn.Name.Name
71 | if strings.HasPrefix(name, "Test") || strings.HasPrefix(name, "Benchmark") {
72 | fnList = append(fnList, name)
73 | }
74 | }
75 | }
76 | if len(fnList) == 0 {
77 | return fmt.Errorf("testing: warning: no tests to run")
78 | }
79 |
80 | if filepath.IsAbs(testFileName) {
81 | dir, _ := filepath.Split(testFileName)
82 | os.Chdir(dir)
83 | }
84 |
85 | gobin, err := exec.LookPath("go")
86 | if err != nil {
87 | return fmt.Errorf("error lookup go: %v", err)
88 | }
89 |
90 | var testArgs []string
91 | testArgs = append(testArgs, "test")
92 | if len(args) > 0 {
93 | testArgs = append(testArgs, args...)
94 | }
95 | testArgs = append(testArgs, "-run", fmt.Sprintf("^(%v)$", strings.Join(fnList, "|")))
96 |
97 | command := exec.Command(gobin, testArgs...)
98 | command.Stdin = os.Stdin
99 | command.Stdout = os.Stdout
100 | command.Stderr = os.Stderr
101 |
102 | return command.Run()
103 | }
104 |
105 | func ApplyBuildTags() {
106 | nexttag := false
107 | for _, arg := range os.Args[1:] {
108 | if nexttag {
109 | var tags buildutil.TagsFlag
110 | tags.Set(arg)
111 |
112 | build.Default.BuildTags = tags
113 | nexttag = false
114 | continue
115 | }
116 | if arg == "-tags" {
117 | nexttag = true
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/pkg/gomod/gomod.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2018 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gomod
6 |
7 | import (
8 | "encoding/json"
9 | "os/exec"
10 | "path/filepath"
11 | "strings"
12 | )
13 |
14 | func LooupModList(dir string) *ModuleList {
15 | data := ListModuleJson(dir)
16 | if data == nil {
17 | return nil
18 | }
19 | ms := parseModuleJson(data)
20 | ms.Dir = dir
21 | return &ms
22 | }
23 |
24 | func LookupModFile(dir string) string {
25 | command := exec.Command("go", "env", "GOMOD")
26 | command.Dir = dir
27 | data, err := command.Output()
28 | if err != nil {
29 | return ""
30 | }
31 | return strings.TrimSpace(string(data))
32 | }
33 |
34 | func ListModuleJson(dir string) []byte {
35 | command := exec.Command("go", "list", "-m", "-json", "all")
36 | command.Dir = dir
37 | data, err := command.Output()
38 | if err != nil {
39 | return nil
40 | }
41 | return data
42 | }
43 |
44 | type ModuleList struct {
45 | Dir string
46 | Module Module
47 | Require []*Module
48 | }
49 |
50 | func makePath(path, dir string, addin string) string {
51 | dir = filepath.ToSlash(dir)
52 | pos := strings.Index(dir, "mod/"+path+"@")
53 | if pos == -1 {
54 | return path
55 | }
56 | return filepath.Join(dir[pos:], addin)
57 | }
58 |
59 | type Package struct {
60 | Dir string
61 | ImportPath string
62 | Name string
63 | Module *Module
64 | }
65 |
66 | func (m *ModuleList) LookupModule(pkgname string) (require *Module, path string, dir string) {
67 | for _, r := range m.Require {
68 | if strings.HasPrefix(pkgname, r.Path) {
69 | addin := pkgname[len(r.Path):]
70 | if r.Replace != nil {
71 | path = makePath(r.Replace.Path, r.Dir, addin)
72 | } else {
73 | path = makePath(r.Path, r.Dir, addin)
74 | }
75 | return r, path, filepath.Join(r.Dir, addin)
76 | }
77 | }
78 | c := exec.Command("go", "list", "-json", "-e", pkgname)
79 | c.Dir = m.Dir
80 | data, err := c.Output()
81 | if err == nil {
82 | var p Package
83 | err = json.Unmarshal(data, &p)
84 | if err == nil {
85 | add := &Module{Path: p.ImportPath, Dir: p.Dir}
86 | m.Require = append(m.Require, add)
87 | return add, p.ImportPath, p.Dir
88 | }
89 | }
90 |
91 | return nil, "", ""
92 | }
93 |
94 | type Module struct {
95 | Path string
96 | Version string
97 | Time string
98 | Dir string
99 | Main bool
100 | Replace *Module
101 | }
102 |
103 | func parseModuleJson(data []byte) ModuleList {
104 | var ms ModuleList
105 | var index int
106 | var tag int
107 | for i, v := range data {
108 | switch v {
109 | case '{':
110 | if tag == 0 {
111 | index = i
112 | }
113 | tag++
114 | case '}':
115 | tag--
116 | if tag == 0 {
117 | var m Module
118 | err := json.Unmarshal(data[index:i+1], &m)
119 | if err == nil {
120 | if m.Main {
121 | ms.Module = m
122 | } else {
123 | ms.Require = append(ms.Require, &m)
124 | }
125 | }
126 | }
127 | }
128 | }
129 | return ms
130 | }
131 |
--------------------------------------------------------------------------------
/gopresent/static/dir.css:
--------------------------------------------------------------------------------
1 | /* copied from $GOROOT/doc/style.css */
2 |
3 | body {
4 | margin: 0;
5 | font-family: Helvetica, Arial, sans-serif;
6 | font-size: 16px;
7 | }
8 | pre,
9 | code {
10 | font-family: Menlo, monospace;
11 | font-size: 14px;
12 | }
13 | pre {
14 | line-height: 18px;
15 | }
16 | pre .comment {
17 | color: #375EAB;
18 | }
19 | pre .highlight,
20 | pre .highlight-comment,
21 | pre .selection-highlight,
22 | pre .selection-highlight-comment {
23 | background: #FFFF00;
24 | }
25 | pre .selection,
26 | pre .selection-comment {
27 | background: #FF9632;
28 | }
29 | pre .ln {
30 | color: #999;
31 | }
32 | body {
33 | color: #222;
34 | }
35 | a,
36 | .exampleHeading .text {
37 | color: #375EAB;
38 | text-decoration: none;
39 | }
40 | a:hover,
41 | .exampleHeading .text:hover {
42 | text-decoration: underline;
43 | }
44 | p,
45 | pre,
46 | ul,
47 | ol {
48 | margin: 20px;
49 | }
50 | pre {
51 | background: #e9e9e9;
52 | padding: 10px;
53 |
54 | -webkit-border-radius: 5px;
55 | -moz-border-radius: 5px;
56 | border-radius: 5px;
57 | }
58 |
59 | h1,
60 | h2,
61 | h3,
62 | h4,
63 | .rootHeading {
64 | margin: 20px 0;
65 | padding: 0;
66 | color: #375EAB;
67 | font-weight: bold;
68 | }
69 | h1 {
70 | font-size: 24px;
71 | }
72 | h2 {
73 | font-size: 20px;
74 | background: #E0EBF5;
75 | padding: 2px 5px;
76 | }
77 | h3 {
78 | font-size: 20px;
79 | }
80 | h3,
81 | h4 {
82 | margin: 20px 5px;
83 | }
84 | h4 {
85 | font-size: 16px;
86 | }
87 |
88 | dl {
89 | margin: 20px;
90 | }
91 | dd {
92 | margin: 2px 20px;
93 | }
94 | dl,
95 | dd {
96 | font-size: 14px;
97 | }
98 | div#nav table td {
99 | vertical-align: top;
100 | }
101 |
102 | div#heading {
103 | float: left;
104 | margin: 0 0 10px 0;
105 | padding: 21px 0;
106 | font-size: 20px;
107 | font-weight: normal;
108 | }
109 | div#heading a {
110 | color: #222;
111 | text-decoration: none;
112 | }
113 |
114 | div#topbar {
115 | background: #E0EBF5;
116 | height: 64px;
117 | }
118 |
119 | body {
120 | text-align: center;
121 | }
122 | div#page,
123 | div#topbar > .container {
124 | clear: both;
125 | text-align: left;
126 | margin-left: auto;
127 | margin-right: auto;
128 | padding: 0 20px;
129 | width: 900px;
130 | }
131 | div#page.wide,
132 | div#topbar > .wide {
133 | width: auto;
134 | }
135 | div#plusone {
136 | float: right;
137 | }
138 |
139 | div#footer {
140 | color: #666;
141 | font-size: 14px;
142 | margin: 40px 0;
143 | }
144 |
145 | div#menu > a,
146 | div#menu > input {
147 | padding: 10px;
148 |
149 | text-decoration: none;
150 | font-size: 16px;
151 |
152 | -webkit-border-radius: 5px;
153 | -moz-border-radius: 5px;
154 | border-radius: 5px;
155 | }
156 | div#menu > a,
157 | div#menu > input {
158 | border: 1px solid #375EAB;
159 | }
160 | div#menu > a {
161 | color: white;
162 | background: #375EAB;
163 | }
164 |
165 | div#menu {
166 | float: right;
167 | min-width: 590px;
168 | padding: 10px 0;
169 | text-align: right;
170 | }
171 | div#menu > a {
172 | margin-right: 5px;
173 | margin-bottom: 10px;
174 |
175 | padding: 10px;
176 | }
177 | div#menu > input {
178 | position: relative;
179 | top: 1px;
180 | width: 60px;
181 | background: white;
182 | color: #222;
183 | }
184 | div#menu > input.inactive {
185 | color: #999;
186 | }
187 |
--------------------------------------------------------------------------------
/finddecl/finddecl.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package finddecl
6 |
7 | import (
8 | "errors"
9 | "fmt"
10 | "go/ast"
11 | "go/parser"
12 | "go/token"
13 | "os"
14 | "path/filepath"
15 | "strconv"
16 |
17 | "github.com/visualfc/gotools/pkg/command"
18 | )
19 |
20 | var Command = &command.Command{
21 | Run: runFindDecl,
22 | UsageLine: "finddecl",
23 | Short: "golang finddecl util",
24 | Long: `golang finddecl util.`,
25 | }
26 | var (
27 | filePath string
28 | fileLine int
29 | )
30 |
31 | func init() {
32 | Command.Flag.StringVar(&filePath, "file", "", "file path")
33 | Command.Flag.IntVar(&fileLine, "line", -1, "file line")
34 | }
35 |
36 | func runFindDecl(cmd *command.Command, args []string) error {
37 | if len(filePath) == 0 || fileLine == -1 {
38 | cmd.Usage()
39 | return os.ErrInvalid
40 | }
41 | if !filepath.IsAbs(filePath) {
42 | dir, err := os.Getwd()
43 | if err != nil {
44 | return err
45 | }
46 | filePath = filepath.Join(dir, filePath)
47 | }
48 |
49 | fset := token.NewFileSet()
50 | f, err := parser.ParseFile(fset, filePath, nil, 0)
51 | if err != nil {
52 | return err
53 | }
54 | decl := findDecl(fset, f, fileLine)
55 | if decl == nil {
56 | fmt.Println("-")
57 | return errors.New("error find decl")
58 | }
59 | printDecl(fset, decl, fileLine)
60 | return nil
61 | }
62 |
63 | type Info struct {
64 | Type string
65 | Name string
66 | BeginLine int
67 | EndLine int
68 | }
69 |
70 | func printDecl(fset *token.FileSet, decl ast.Decl, line int) {
71 | var tag string
72 | var name string
73 |
74 | tag = "-"
75 | name = "-"
76 | switch d := decl.(type) {
77 | case *ast.GenDecl:
78 | switch d.Tok {
79 | case token.IMPORT:
80 | tag = "import"
81 | if len(d.Specs) > 0 {
82 | if ts := d.Specs[0].(*ast.ImportSpec); ts != nil {
83 | name, _ = strconv.Unquote(ts.Path.Value)
84 | }
85 | }
86 | case token.TYPE:
87 | tag = "type"
88 | if len(d.Specs) > 0 {
89 | if ts := d.Specs[0].(*ast.TypeSpec); ts != nil {
90 | name = ts.Name.Name
91 | switch ts.Type.(type) {
92 | case *ast.StructType:
93 | tag = "struct"
94 | case *ast.InterfaceType:
95 | tag = "interface"
96 | default:
97 | tag = "type"
98 | }
99 | }
100 | }
101 | case token.VAR, token.CONST:
102 | tag = d.Tok.String()
103 | var testName string
104 | for _, ds := range d.Specs {
105 | if ts := ds.(*ast.ValueSpec); ts != nil {
106 | name = ts.Names[0].Name
107 | for _, n := range ts.Names {
108 | if line >= fset.Position(n.Pos()).Line && line <= fset.Position(n.End()).Line {
109 | testName = n.Name
110 | break
111 | }
112 | }
113 | }
114 | }
115 | if testName != "" {
116 | name = testName
117 | }
118 | default:
119 | tag = d.Tok.String()
120 | }
121 | case *ast.FuncDecl:
122 | tag = "func"
123 | name = d.Name.Name
124 | }
125 | fmt.Println(tag, name, fset.Position(decl.Pos()).Line, fset.Position(decl.End()).Line)
126 | }
127 |
128 | func findDecl(fset *token.FileSet, file *ast.File, line int) ast.Decl {
129 | for _, decl := range file.Decls {
130 | if line >= fset.Position(decl.Pos()).Line && line <= fset.Position(decl.End()).Line {
131 | return decl
132 | }
133 | }
134 | return nil
135 | }
136 |
--------------------------------------------------------------------------------
/pkg/stdlib/mkpkglist.go:
--------------------------------------------------------------------------------
1 | // +build ignore
2 |
3 | package main
4 |
5 | import (
6 | "bytes"
7 | "fmt"
8 | "go/format"
9 | "io/ioutil"
10 | "log"
11 | "os/exec"
12 | "strings"
13 | )
14 |
15 | var basePkgList = `
16 | archive/tar
17 | archive/zip
18 | bufio
19 | bytes
20 | compress/bzip2
21 | compress/flate
22 | compress/gzip
23 | compress/lzw
24 | compress/zlib
25 | container/heap
26 | container/list
27 | container/ring
28 | context
29 | crypto
30 | crypto/aes
31 | crypto/cipher
32 | crypto/des
33 | crypto/dsa
34 | crypto/ecdsa
35 | crypto/elliptic
36 | crypto/hmac
37 | crypto/md5
38 | crypto/rand
39 | crypto/rc4
40 | crypto/rsa
41 | crypto/sha1
42 | crypto/sha256
43 | crypto/sha512
44 | crypto/subtle
45 | crypto/tls
46 | crypto/x509
47 | crypto/x509/pkix
48 | database/sql
49 | database/sql/driver
50 | debug/dwarf
51 | debug/elf
52 | debug/gosym
53 | debug/macho
54 | debug/pe
55 | debug/plan9obj
56 | encoding
57 | encoding/ascii85
58 | encoding/asn1
59 | encoding/base32
60 | encoding/base64
61 | encoding/binary
62 | encoding/csv
63 | encoding/gob
64 | encoding/hex
65 | encoding/json
66 | encoding/pem
67 | encoding/xml
68 | errors
69 | expvar
70 | flag
71 | fmt
72 | go/ast
73 | go/build
74 | go/constant
75 | go/doc
76 | go/format
77 | go/importer
78 | go/parser
79 | go/printer
80 | go/scanner
81 | go/token
82 | go/types
83 | hash
84 | hash/adler32
85 | hash/crc32
86 | hash/crc64
87 | hash/fnv
88 | html
89 | html/template
90 | image
91 | image/color
92 | image/color/palette
93 | image/draw
94 | image/gif
95 | image/jpeg
96 | image/png
97 | index/suffixarray
98 | io
99 | io/ioutil
100 | log
101 | log/syslog
102 | math
103 | math/big
104 | math/bits
105 | math/cmplx
106 | math/rand
107 | mime
108 | mime/multipart
109 | mime/quotedprintable
110 | net
111 | net/http
112 | net/http/cgi
113 | net/http/cookiejar
114 | net/http/fcgi
115 | net/http/httptest
116 | net/http/httptrace
117 | net/http/httputil
118 | net/http/pprof
119 | net/mail
120 | net/rpc
121 | net/rpc/jsonrpc
122 | net/smtp
123 | net/textproto
124 | net/url
125 | os
126 | os/exec
127 | os/signal
128 | os/user
129 | path
130 | path/filepath
131 | plugin
132 | reflect
133 | regexp
134 | regexp/syntax
135 | runtime
136 | runtime/cgo
137 | runtime/debug
138 | runtime/pprof
139 | runtime/race
140 | runtime/trace
141 | sort
142 | strconv
143 | strings
144 | sync
145 | sync/atomic
146 | syscall
147 | testing
148 | testing/iotest
149 | testing/quick
150 | text/scanner
151 | text/tabwriter
152 | text/template
153 | text/template/parse
154 | time
155 | unicode
156 | unicode/utf16
157 | unicode/utf8
158 | unsafe
159 | `
160 |
161 | func main() {
162 | cmd := exec.Command("go", "list", "std")
163 | out, err := cmd.Output()
164 | if err != nil {
165 | log.Fatalln(err)
166 | }
167 | var pkgList []string
168 | for _, v := range strings.Split(string(out), "\n") {
169 | if v == "" {
170 | continue
171 | }
172 | if strings.HasPrefix(v, "vendor/") {
173 | continue
174 | }
175 | pkgList = append(pkgList, v)
176 | }
177 |
178 | var list []string
179 | index := 0
180 | for _, v := range pkgList {
181 | v = strings.TrimSpace(v)
182 | if v == "" {
183 | continue
184 | }
185 | v = "\"" + v + "\""
186 | if index%4 == 0 && index != 0 {
187 | v = "\n" + v
188 | }
189 | list = append(list, v)
190 | index++
191 | }
192 | var buf bytes.Buffer
193 | outf := func(format string, args ...interface{}) {
194 | fmt.Fprintf(&buf, format, args...)
195 | }
196 | outf("// AUTO-GENERATED BY mkpkglist.go\n\n")
197 | outf("package stdlib\n")
198 | outf("var Packages = []string{\n")
199 | outf(strings.Join(list, ","))
200 | outf("}\n")
201 | outf(`
202 | func IsStdPkg(pkg string) bool {
203 | for _, v := range Packages {
204 | if v == pkg {
205 | return true
206 | }
207 | }
208 | return false
209 | }`)
210 | fmtbuf, err := format.Source(buf.Bytes())
211 | if err != nil {
212 | log.Fatal(err)
213 | }
214 | //os.Stdout.Write(fmtbuf)
215 | ioutil.WriteFile("./pkglist.go", fmtbuf, 0777)
216 | }
217 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
2 | github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 | github.com/visualfc/gomod v0.1.2 h1:7qfPmifcA8r/0ZTpTPZQqsm5aJUiQ/EeyHEENPyywDg=
6 | github.com/visualfc/gomod v0.1.2/go.mod h1:rV5goiA/Ul6yT8X2eDnc/dl0dVy0cDHJLZVOuJ8PdmM=
7 | github.com/visualfc/goversion v1.1.0 h1:EN0YQGRkeGoWTPxPNTnbhyNQyas5leKH5U5lL4t8lRE=
8 | github.com/visualfc/goversion v1.1.0/go.mod h1:Gr3s6bW8NTomhheImwAttqno97Mw6pAnFn2dU8/EMa8=
9 | github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
10 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
11 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
12 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
13 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
14 | golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
15 | golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
16 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
17 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
18 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
19 | golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
20 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
21 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
22 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
23 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
24 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
25 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
26 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
27 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
29 | golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
30 | golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
31 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
32 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
33 | golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
34 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
35 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
36 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
37 | golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
38 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
39 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
40 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
41 | golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
42 | golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
43 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
44 |
--------------------------------------------------------------------------------
/pkg/stdlib/pkglist.go:
--------------------------------------------------------------------------------
1 | // AUTO-GENERATED BY mkpkglist.go
2 |
3 | package stdlib
4 |
5 | var Packages = []string{
6 | "archive/tar", "archive/zip", "bufio", "bytes",
7 | "compress/bzip2", "compress/flate", "compress/gzip", "compress/lzw",
8 | "compress/zlib", "container/heap", "container/list", "container/ring",
9 | "context", "crypto", "crypto/aes", "crypto/cipher",
10 | "crypto/des", "crypto/dsa", "crypto/ecdh", "crypto/ecdsa",
11 | "crypto/ed25519", "crypto/elliptic", "crypto/hmac", "crypto/internal/alias",
12 | "crypto/internal/bigmod", "crypto/internal/boring", "crypto/internal/boring/bbig", "crypto/internal/boring/bcache",
13 | "crypto/internal/boring/sig", "crypto/internal/edwards25519", "crypto/internal/edwards25519/field", "crypto/internal/nistec",
14 | "crypto/internal/nistec/fiat", "crypto/internal/randutil", "crypto/md5", "crypto/rand",
15 | "crypto/rc4", "crypto/rsa", "crypto/sha1", "crypto/sha256",
16 | "crypto/sha512", "crypto/subtle", "crypto/tls", "crypto/x509",
17 | "crypto/x509/internal/macos", "crypto/x509/pkix", "database/sql", "database/sql/driver",
18 | "debug/buildinfo", "debug/dwarf", "debug/elf", "debug/gosym",
19 | "debug/macho", "debug/pe", "debug/plan9obj", "embed",
20 | "embed/internal/embedtest", "encoding", "encoding/ascii85", "encoding/asn1",
21 | "encoding/base32", "encoding/base64", "encoding/binary", "encoding/csv",
22 | "encoding/gob", "encoding/hex", "encoding/json", "encoding/pem",
23 | "encoding/xml", "errors", "expvar", "flag",
24 | "fmt", "go/ast", "go/build", "go/build/constraint",
25 | "go/constant", "go/doc", "go/doc/comment", "go/format",
26 | "go/importer", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter",
27 | "go/internal/typeparams", "go/parser", "go/printer", "go/scanner",
28 | "go/token", "go/types", "hash", "hash/adler32",
29 | "hash/crc32", "hash/crc64", "hash/fnv", "hash/maphash",
30 | "html", "html/template", "image", "image/color",
31 | "image/color/palette", "image/draw", "image/gif", "image/internal/imageutil",
32 | "image/jpeg", "image/png", "index/suffixarray", "internal/abi",
33 | "internal/buildcfg", "internal/bytealg", "internal/cfg", "internal/coverage",
34 | "internal/coverage/calloc", "internal/coverage/cformat", "internal/coverage/cmerge", "internal/coverage/decodecounter",
35 | "internal/coverage/decodemeta", "internal/coverage/encodecounter", "internal/coverage/encodemeta", "internal/coverage/pods",
36 | "internal/coverage/rtcov", "internal/coverage/slicereader", "internal/coverage/slicewriter", "internal/coverage/stringtab",
37 | "internal/coverage/test", "internal/coverage/uleb128", "internal/cpu", "internal/dag",
38 | "internal/diff", "internal/fmtsort", "internal/fuzz", "internal/goarch",
39 | "internal/godebug", "internal/goexperiment", "internal/goos", "internal/goroot",
40 | "internal/goversion", "internal/intern", "internal/itoa", "internal/lazyregexp",
41 | "internal/lazytemplate", "internal/nettrace", "internal/obscuretestdata", "internal/oserror",
42 | "internal/pkgbits", "internal/platform", "internal/poll", "internal/profile",
43 | "internal/race", "internal/reflectlite", "internal/safefilepath", "internal/saferio",
44 | "internal/singleflight", "internal/syscall/execenv", "internal/syscall/unix", "internal/sysinfo",
45 | "internal/testenv", "internal/testlog", "internal/testpty", "internal/trace",
46 | "internal/txtar", "internal/types/errors", "internal/unsafeheader", "internal/xcoff",
47 | "io", "io/fs", "io/ioutil", "log",
48 | "log/syslog", "math", "math/big", "math/bits",
49 | "math/cmplx", "math/rand", "mime", "mime/multipart",
50 | "mime/quotedprintable", "net", "net/http", "net/http/cgi",
51 | "net/http/cookiejar", "net/http/fcgi", "net/http/httptest", "net/http/httptrace",
52 | "net/http/httputil", "net/http/internal", "net/http/internal/ascii", "net/http/internal/testcert",
53 | "net/http/pprof", "net/internal/socktest", "net/mail", "net/netip",
54 | "net/rpc", "net/rpc/jsonrpc", "net/smtp", "net/textproto",
55 | "net/url", "os", "os/exec", "os/exec/internal/fdtest",
56 | "os/signal", "os/user", "path", "path/filepath",
57 | "plugin", "reflect", "reflect/internal/example1", "reflect/internal/example2",
58 | "regexp", "regexp/syntax", "runtime", "runtime/cgo",
59 | "runtime/coverage", "runtime/debug", "runtime/internal/atomic", "runtime/internal/math",
60 | "runtime/internal/startlinetest", "runtime/internal/sys", "runtime/metrics", "runtime/pprof",
61 | "runtime/race", "runtime/race/internal/amd64v1", "runtime/trace", "sort",
62 | "strconv", "strings", "sync", "sync/atomic",
63 | "syscall", "testing", "testing/fstest", "testing/internal/testdeps",
64 | "testing/iotest", "testing/quick", "text/scanner", "text/tabwriter",
65 | "text/template", "text/template/parse", "time", "time/tzdata",
66 | "unicode", "unicode/utf16", "unicode/utf8", "unsafe"}
67 |
68 | func IsStdPkg(pkg string) bool {
69 | for _, v := range Packages {
70 | if v == pkg {
71 | return true
72 | }
73 | }
74 | return false
75 | }
76 |
--------------------------------------------------------------------------------
/jsonfmt/jsonfmt.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package jsonfmt
6 |
7 | import (
8 | "bytes"
9 | "encoding/json"
10 | "fmt"
11 | "io"
12 | "io/ioutil"
13 | "os"
14 | "path/filepath"
15 | "strings"
16 |
17 | "github.com/visualfc/gotools/pkg/command"
18 | "github.com/visualfc/gotools/pkg/godiff"
19 | )
20 |
21 | var Command = &command.Command{
22 | Run: runJsonFmt,
23 | UsageLine: "jsonfmt",
24 | Short: "json format util",
25 | Long: `json format util.`,
26 | }
27 |
28 | var (
29 | jsonFmtList bool
30 | jsonFmtCompact bool
31 | jsonFmtWrite bool
32 | jsonFmtDiff bool
33 | jsonTabWidth int
34 | jsonTabIndent bool
35 | )
36 |
37 | func init() {
38 | Command.Flag.BoolVar(&jsonFmtList, "l", false, "list files whose formatting differs")
39 | Command.Flag.BoolVar(&jsonFmtCompact, "c", false, "compact json")
40 | Command.Flag.BoolVar(&jsonFmtWrite, "w", false, "write result to (source) file instead of stdout")
41 | Command.Flag.BoolVar(&jsonFmtDiff, "d", false, "display diffs instead of rewriting files")
42 | Command.Flag.IntVar(&jsonTabWidth, "tabwidth", 4, "tab width")
43 | Command.Flag.BoolVar(&jsonTabIndent, "tabs", false, "indent with tabs")
44 | }
45 |
46 | func runJsonFmt(cmd *command.Command, args []string) error {
47 | opt := &JsonFmtOption{}
48 | opt.List = jsonFmtList
49 | opt.Compact = jsonFmtCompact
50 | opt.IndentTab = jsonTabIndent
51 | opt.TabWidth = jsonTabWidth
52 | opt.Write = jsonFmtWrite
53 | opt.Diff = jsonFmtDiff
54 |
55 | if len(args) == 0 {
56 | if err := processJsonFile("", cmd.Stdin, cmd.Stdout, true, opt); err != nil {
57 | return err
58 | }
59 | } else {
60 | for _, path := range args {
61 | switch dir, err := os.Stat(path); {
62 | case err != nil:
63 | reportJsonError(err)
64 | case dir.IsDir():
65 | filepath.Walk(path, func(path string, f os.FileInfo, err error) error {
66 | if err == nil && isJsonFile(f) {
67 | err = processJsonFile(path, nil, cmd.Stdout, false, opt)
68 | }
69 | if err != nil {
70 | reportJsonError(err)
71 | }
72 | return nil
73 | })
74 | default:
75 | if err := processJsonFile(path, nil, cmd.Stdout, false, opt); err != nil {
76 | reportJsonError(err)
77 | }
78 | }
79 | }
80 | }
81 | return nil
82 | }
83 |
84 | type JsonFmtOption struct {
85 | List bool
86 | Compact bool
87 | Format bool
88 | Write bool
89 | Diff bool
90 | IndentTab bool
91 | TabWidth int
92 | }
93 |
94 | func isJsonFile(f os.FileInfo) bool {
95 | // ignore non-Go files
96 | name := f.Name()
97 | return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".json")
98 | }
99 |
100 | func reportJsonError(err error) {
101 | fmt.Fprintf(os.Stderr, "%s\n", err)
102 | }
103 |
104 | func processJson(filename string, src []byte, opt *JsonFmtOption) ([]byte, error) {
105 | if opt.Compact {
106 | var out bytes.Buffer
107 | err := json.Compact(&out, src)
108 | if err != nil {
109 | return nil, err
110 | }
111 | return out.Bytes(), nil
112 | } else {
113 | var out bytes.Buffer
114 | var err error
115 | if opt.IndentTab {
116 | err = json.Indent(&out, src, "", "\t")
117 | } else {
118 | var indent string
119 | for i := 0; i < opt.TabWidth; i++ {
120 | indent += " "
121 | }
122 | err = json.Indent(&out, src, "", indent)
123 | }
124 | if err != nil {
125 | return nil, err
126 | }
127 | return out.Bytes(), nil
128 | }
129 | return src, nil
130 | }
131 |
132 | func processJsonFile(filename string, in io.Reader, out io.Writer, stdin bool, opt *JsonFmtOption) error {
133 | if in == nil {
134 | f, err := os.Open(filename)
135 | if err != nil {
136 | return err
137 | }
138 | defer f.Close()
139 | in = f
140 | }
141 |
142 | src, err := ioutil.ReadAll(in)
143 | if err != nil {
144 | return err
145 | }
146 |
147 | res, err := processJson(filename, src, opt)
148 | if err != nil {
149 | return err
150 | }
151 |
152 | if !bytes.Equal(src, res) {
153 | // formatting has changed
154 | if opt.List {
155 | fmt.Fprintln(out, filename)
156 | }
157 | if opt.Write {
158 | err = ioutil.WriteFile(filename, res, 0)
159 | if err != nil {
160 | return err
161 | }
162 | }
163 | if opt.Diff {
164 | data, err := diffJson(src, res)
165 | if err != nil {
166 | return fmt.Errorf("computing diff: %s", err)
167 | }
168 | fmt.Fprintf(out, "diff %s json/%s\n", filename, filename)
169 | out.Write(data)
170 | }
171 | }
172 |
173 | if !opt.List && !opt.Write && !opt.Diff {
174 | _, err = out.Write(res)
175 | }
176 |
177 | return err
178 | }
179 |
180 | func diffJson(src, res []byte) (data []byte, err error) {
181 | var dataTmp string // because godiff.UnifiedDiffString returns string
182 | dataTmp, err = godiff.UnifiedDiffString(string(src), string(res))
183 | data = []byte(dataTmp)
184 | return
185 | }
186 |
--------------------------------------------------------------------------------
/gofmt/gofmt.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package gofmt
6 |
7 | import (
8 | "bytes"
9 | "fmt"
10 | "go/token"
11 | "io"
12 | "io/ioutil"
13 | "os"
14 | "path/filepath"
15 | "runtime"
16 | "strings"
17 | "sync"
18 |
19 | "github.com/visualfc/gotools/pkg/command"
20 | "github.com/visualfc/gotools/pkg/godiff"
21 | "golang.org/x/tools/imports"
22 | )
23 |
24 | var Command = &command.Command{
25 | Run: runGofmt,
26 | UsageLine: "gofmt [flags] [path ...]",
27 | Short: "gofmt formats Go source.",
28 | Long: `gofmt formats Go source`,
29 | }
30 |
31 | var (
32 | gofmtList bool
33 | gofmtWrite bool
34 | gofmtDiff bool
35 | gofmtAllErrors bool
36 | gofmtFixImports bool
37 | gofmtSortImports bool
38 | gofmtUseGodiffLib bool
39 |
40 | // layout control
41 | gofmtComments bool
42 | gofmtTabWidth int
43 | gofmtTabIndent bool
44 | )
45 |
46 | //func init
47 | func init() {
48 | Command.Flag.BoolVar(&gofmtList, "l", false, "list files whose formatting differs from goimport's")
49 | Command.Flag.BoolVar(&gofmtWrite, "w", false, "write result to (source) file instead of stdout")
50 | Command.Flag.BoolVar(&gofmtDiff, "d", false, "display diffs instead of rewriting files")
51 | Command.Flag.BoolVar(&gofmtAllErrors, "e", false, "report all errors (not just the first 10 on different lines)")
52 | Command.Flag.BoolVar(&gofmtFixImports, "fiximports", false, "updates Go import lines, adding missing ones and removing unreferenced ones")
53 | Command.Flag.BoolVar(&gofmtSortImports, "sortimports", false, "sort Go import lines use goimports style")
54 | Command.Flag.BoolVar(&gofmtUseGodiffLib, "godiff", true, "diff use godiff library")
55 |
56 | // layout control
57 | Command.Flag.BoolVar(&gofmtComments, "comments", true, "print comments")
58 | Command.Flag.IntVar(&gofmtTabWidth, "tabwidth", 8, "tab width")
59 | Command.Flag.BoolVar(&gofmtTabIndent, "tabs", true, "indent with tabs")
60 | }
61 |
62 | var (
63 | fileSet = token.NewFileSet() // per process FileSet
64 | exitCode = 0
65 |
66 | initModesOnce sync.Once // guards calling initModes
67 | //parserMode parser.Mode
68 | //printerMode printer.Mode
69 | options *imports.Options
70 | )
71 |
72 | func runGofmt(cmd *command.Command, args []string) error {
73 | runtime.GOMAXPROCS(runtime.NumCPU())
74 |
75 | if gofmtTabWidth < 0 {
76 | return os.ErrInvalid
77 | }
78 |
79 | if gofmtFixImports {
80 | gofmtSortImports = true
81 | }
82 |
83 | options = &imports.Options{
84 | FormatOnly: !gofmtFixImports,
85 | TabWidth: gofmtTabWidth,
86 | TabIndent: gofmtTabIndent,
87 | Comments: gofmtComments,
88 | AllErrors: gofmtAllErrors,
89 | Fragment: true,
90 | }
91 |
92 | if len(args) == 0 {
93 | return processFile("", cmd.Stdin, cmd.Stdout, true)
94 | }
95 | for _, path := range args {
96 | switch dir, err := os.Stat(path); {
97 | case err != nil:
98 | fmt.Fprintln(cmd.Stderr, err)
99 | case dir.IsDir():
100 | walkDir(path)
101 | default:
102 | if err := processFile(path, nil, cmd.Stdout, false); err != nil {
103 | fmt.Fprintln(cmd.Stderr, err)
104 | }
105 | }
106 | }
107 | return nil
108 | }
109 |
110 | func isGoFile(f os.FileInfo) bool {
111 | // ignore non-Go files
112 | name := f.Name()
113 | return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
114 | }
115 |
116 | func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
117 | var src []byte
118 | var err error
119 | if in == nil {
120 | src, err = ioutil.ReadFile(filename)
121 | } else {
122 | src, err = ioutil.ReadAll(in)
123 | }
124 | if err != nil {
125 | return err
126 | }
127 |
128 | res, err := imports.Process(filename, src, options)
129 | if err != nil {
130 | return err
131 | }
132 |
133 | if !bytes.Equal(src, res) {
134 | // formatting has changed
135 | if gofmtList {
136 | fmt.Fprintln(out, filename)
137 | }
138 | if gofmtWrite {
139 | err = ioutil.WriteFile(filename, res, 0)
140 | if err != nil {
141 | return err
142 | }
143 | }
144 | if gofmtDiff {
145 | var data []byte
146 | var err error
147 | if gofmtUseGodiffLib {
148 | var dataTmp string // because godiff.UnifiedDiffString returns string
149 | dataTmp, err = godiff.UnifiedDiffString(string(src), string(res))
150 | data = []byte(dataTmp)
151 | } else {
152 | data, err = godiff.UnifiedDiffBytesByCmd(src, res)
153 | }
154 | if err != nil {
155 | return fmt.Errorf("computing diff: %s", err)
156 | }
157 | fmt.Fprintf(out, "diff %s gofmt/%s\n", filename, filename)
158 | out.Write(data)
159 | }
160 | }
161 |
162 | if !gofmtList && !gofmtWrite && !gofmtDiff {
163 | _, err = out.Write(res)
164 | }
165 |
166 | return err
167 | }
168 |
169 | func visitFile(path string, f os.FileInfo, err error) error {
170 | if err == nil && isGoFile(f) {
171 | err = processFile(path, nil, os.Stdout, false)
172 | }
173 | return err
174 | }
175 |
176 | func walkDir(path string) {
177 | filepath.Walk(path, visitFile)
178 | }
179 |
--------------------------------------------------------------------------------
/pkg/pkgwalk/allpackages.go:
--------------------------------------------------------------------------------
1 | // Copyright 2014 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package buildutil provides utilities related to the go/build
6 | // package in the standard library.
7 | //
8 | // All I/O is done via the build.Context file system interface, which must
9 | // be concurrency-safe.
10 | package pkgwalk
11 |
12 | import (
13 | "go/build"
14 | "io/ioutil"
15 | "os"
16 | "path/filepath"
17 | "sort"
18 | "strings"
19 | "sync"
20 | )
21 |
22 | // AllPackages returns the package path of each Go package in any source
23 | // directory of the specified build context (e.g. $GOROOT or an element
24 | // of $GOPATH). Errors are ignored. The results are sorted.
25 | // All package paths are canonical, and thus may contain "/vendor/".
26 | //
27 | // The result may include import paths for directories that contain no
28 | // *.go files, such as "archive" (in $GOROOT/src).
29 | //
30 | // All I/O is done via the build.Context file system interface,
31 | // which must be concurrency-safe.
32 | //
33 | func AllPackages(ctxt *build.Context) []string {
34 | var list []string
35 | ForEachPackage(ctxt, func(pkg string, _ error) {
36 | list = append(list, pkg)
37 | })
38 | sort.Strings(list)
39 | return list
40 | }
41 |
42 | // ForEachPackage calls the found function with the package path of
43 | // each Go package it finds in any source directory of the specified
44 | // build context (e.g. $GOROOT or an element of $GOPATH).
45 | // All package paths are canonical, and thus may contain "/vendor/".
46 | //
47 | // If the package directory exists but could not be read, the second
48 | // argument to the found function provides the error.
49 | //
50 | // All I/O is done via the build.Context file system interface,
51 | // which must be concurrency-safe.
52 | //
53 | func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) {
54 | ch := make(chan item)
55 |
56 | var wg sync.WaitGroup
57 | for _, root := range ctxt.SrcDirs() {
58 | root := root
59 | wg.Add(1)
60 | go func() {
61 | allPackages(ctxt, root, ch)
62 | wg.Done()
63 | }()
64 | }
65 | go func() {
66 | wg.Wait()
67 | close(ch)
68 | }()
69 |
70 | // All calls to found occur in the caller's goroutine.
71 | for i := range ch {
72 | found(i.importPath, i.err)
73 | }
74 | }
75 |
76 | type item struct {
77 | importPath string
78 | err error // (optional)
79 | }
80 |
81 | // We use a process-wide counting semaphore to limit
82 | // the number of parallel calls to ReadDir.
83 | var ioLimit = make(chan bool, 20)
84 |
85 | func allPackages(ctxt *build.Context, root string, ch chan<- item) {
86 | root = filepath.Clean(root) + string(os.PathSeparator)
87 |
88 | var wg sync.WaitGroup
89 |
90 | var walkDir func(dir string)
91 | walkDir = func(dir string) {
92 | // Avoid .foo, _foo, and testdata directory trees.
93 | base := filepath.Base(dir)
94 | if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" {
95 | return
96 | }
97 |
98 | pkg := filepath.ToSlash(strings.TrimPrefix(dir, root))
99 |
100 | // Prune search if we encounter any of these import paths.
101 | switch pkg {
102 | case "builtin":
103 | return
104 | }
105 |
106 | ioLimit <- true
107 | files, err := ReadDir(ctxt, dir)
108 | <-ioLimit
109 | if pkg != "" || err != nil {
110 | ch <- item{pkg, err}
111 | }
112 | for _, fi := range files {
113 | fi := fi
114 | if fi.IsDir() {
115 | wg.Add(1)
116 | go func() {
117 | walkDir(filepath.Join(dir, fi.Name()))
118 | wg.Done()
119 | }()
120 | }
121 | }
122 | }
123 |
124 | walkDir(root)
125 | wg.Wait()
126 | }
127 |
128 | // ExpandPatterns returns the set of packages matched by patterns,
129 | // which may have the following forms:
130 | //
131 | // golang.org/x/tools/cmd/guru # a single package
132 | // golang.org/x/tools/... # all packages beneath dir
133 | // ... # the entire workspace.
134 | //
135 | // Order is significant: a pattern preceded by '-' removes matching
136 | // packages from the set. For example, these patterns match all encoding
137 | // packages except encoding/xml:
138 | //
139 | // encoding/... -encoding/xml
140 | //
141 | func ExpandPatterns(ctxt *build.Context, patterns []string) map[string]bool {
142 | // TODO(adonovan): support other features of 'go list':
143 | // - "std"/"cmd"/"all" meta-packages
144 | // - "..." not at the end of a pattern
145 | // - relative patterns using "./" or "../" prefix
146 |
147 | pkgs := make(map[string]bool)
148 | doPkg := func(pkg string, neg bool) {
149 | if neg {
150 | delete(pkgs, pkg)
151 | } else {
152 | pkgs[pkg] = true
153 | }
154 | }
155 |
156 | // Scan entire workspace if wildcards are present.
157 | // TODO(adonovan): opt: scan only the necessary subtrees of the workspace.
158 | var all []string
159 | for _, arg := range patterns {
160 | if strings.HasSuffix(arg, "...") {
161 | all = AllPackages(ctxt)
162 | break
163 | }
164 | }
165 |
166 | for _, arg := range patterns {
167 | if arg == "" {
168 | continue
169 | }
170 |
171 | neg := arg[0] == '-'
172 | if neg {
173 | arg = arg[1:]
174 | }
175 |
176 | if arg == "..." {
177 | // ... matches all packages
178 | for _, pkg := range all {
179 | doPkg(pkg, neg)
180 | }
181 | } else if dir := strings.TrimSuffix(arg, "/..."); dir != arg {
182 | // dir/... matches all packages beneath dir
183 | for _, pkg := range all {
184 | if strings.HasPrefix(pkg, dir) &&
185 | (len(pkg) == len(dir) || pkg[len(dir)] == '/') {
186 | doPkg(pkg, neg)
187 | }
188 | }
189 | } else {
190 | // single package
191 | doPkg(arg, neg)
192 | }
193 | }
194 |
195 | return pkgs
196 | }
197 |
198 | func ReadDir(ctxt *build.Context, path string) ([]os.FileInfo, error) {
199 | if ctxt.ReadDir != nil {
200 | return ctxt.ReadDir(path)
201 | }
202 | return ioutil.ReadDir(path)
203 | }
204 |
--------------------------------------------------------------------------------
/pkg/srcimporter/srcimporter.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package srcimporter implements importing directly
6 | // from source files rather than installed packages.
7 | package srcimporter
8 |
9 | import (
10 | "fmt"
11 | "go/ast"
12 | "go/build"
13 | "go/importer"
14 | "go/parser"
15 | "go/token"
16 | "go/types"
17 | "io"
18 | "os"
19 | "path/filepath"
20 | "sync"
21 | )
22 |
23 | // An Importer provides the context for importing packages from source code.
24 | type Importer struct {
25 | ctxt *build.Context
26 | fset *token.FileSet
27 | sizes types.Sizes
28 | packages map[string]*types.Package
29 | }
30 |
31 | // NewImporter returns a new Importer for the given context, file set, and map
32 | // of packages. The context is used to resolve import paths to package paths,
33 | // and identifying the files belonging to the package. If the context provides
34 | // non-nil file system functions, they are used instead of the regular package
35 | // os functions. The file set is used to track position information of package
36 | // files; and imported packages are added to the packages map.
37 | func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Package) *Importer {
38 | return &Importer{
39 | ctxt: ctxt,
40 | fset: fset,
41 | sizes: types.SizesFor(ctxt.Compiler, ctxt.GOARCH), // uses go/types default if GOARCH not found
42 | packages: packages,
43 | }
44 | }
45 |
46 | // Importing is a sentinel taking the place in Importer.packages
47 | // for a package that is in the process of being imported.
48 | var importing types.Package
49 |
50 | // Import(path) is a shortcut for ImportFrom(path, ".", 0).
51 | func (p *Importer) Import(path string) (*types.Package, error) {
52 | return p.ImportFrom(path, ".", 0) // use "." rather than "" (see issue #24441)
53 | }
54 |
55 | // ImportFrom imports the package with the given import path resolved from the given srcDir,
56 | // adds the new package to the set of packages maintained by the importer, and returns the
57 | // package. Package path resolution and file system operations are controlled by the context
58 | // maintained with the importer. The import mode must be zero but is otherwise ignored.
59 | // Packages that are not comprised entirely of pure Go files may fail to import because the
60 | // type checker may not be able to determine all exported entities (e.g. due to cgo dependencies).
61 | func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
62 | if mode != 0 {
63 | panic("non-zero import mode")
64 | }
65 |
66 | // if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
67 | // srcDir = abs
68 | // }
69 | var bp *build.Package
70 | var err error
71 | if srcDir != "" && srcDir != "." {
72 | bp, err = p.ctxt.ImportDir(srcDir, 0)
73 | bp.ImportPath = path
74 | } else {
75 | bp, err = p.ctxt.Import(path, srcDir, 0)
76 | }
77 | if err != nil {
78 | return nil, err // err may be *build.NoGoError - return as is
79 | }
80 |
81 | // package unsafe is known to the type checker
82 | if bp.ImportPath == "unsafe" {
83 | return types.Unsafe, nil
84 | }
85 |
86 | // no need to re-import if the package was imported completely before
87 | pkg := p.packages[bp.ImportPath]
88 | if pkg != nil {
89 | if pkg == &importing {
90 | return nil, fmt.Errorf("import cycle through package %q", bp.ImportPath)
91 | }
92 | if !pkg.Complete() {
93 | // Package exists but is not complete - we cannot handle this
94 | // at the moment since the source importer replaces the package
95 | // wholesale rather than augmenting it (see #19337 for details).
96 | // Return incomplete package with error (see #16088).
97 | return pkg, fmt.Errorf("reimported partially imported package %q", bp.ImportPath)
98 | }
99 | return pkg, nil
100 | }
101 |
102 | p.packages[bp.ImportPath] = &importing
103 | defer func() {
104 | // clean up in case of error
105 | // TODO(gri) Eventually we may want to leave a (possibly empty)
106 | // package in the map in all cases (and use that package to
107 | // identify cycles). See also issue 16088.
108 | if p.packages[bp.ImportPath] == &importing {
109 | p.packages[bp.ImportPath] = nil
110 | }
111 | }()
112 |
113 | var filenames []string
114 | filenames = append(filenames, bp.GoFiles...)
115 | filenames = append(filenames, bp.CgoFiles...)
116 |
117 | files, err := p.parseFiles(bp.Dir, filenames)
118 | if err != nil {
119 | return nil, err
120 | }
121 |
122 | // type-check package files
123 | var firstHardErr error
124 | conf := types.Config{
125 | IgnoreFuncBodies: true,
126 | FakeImportC: true,
127 | // continue type-checking after the first error
128 | Error: func(err error) {
129 | if firstHardErr == nil && !err.(types.Error).Soft {
130 | firstHardErr = err
131 | }
132 | },
133 | Importer: importer.Default(),
134 | Sizes: p.sizes,
135 | }
136 | pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil)
137 | if pkg == nil {
138 | // If there was a hard error it is possibly unsafe
139 | // to use the package as it may not be fully populated.
140 | // Do not return it (see also #20837, #20855).
141 | if firstHardErr != nil {
142 | err = firstHardErr // give preference to first hard error over any soft error
143 | }
144 | return pkg, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err)
145 | }
146 | // if firstHardErr != nil {
147 | // // this can only happen if we have a bug in go/types
148 | // panic("package is not safe yet no error was returned")
149 | // }
150 |
151 | p.packages[bp.ImportPath] = pkg
152 | return pkg, nil
153 | }
154 |
155 | func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, error) {
156 | // use build.Context's OpenFile if there is one
157 | open := p.ctxt.OpenFile
158 | if open == nil {
159 | open = func(name string) (io.ReadCloser, error) { return os.Open(name) }
160 | }
161 |
162 | files := make([]*ast.File, len(filenames))
163 | errors := make([]error, len(filenames))
164 |
165 | var wg sync.WaitGroup
166 | wg.Add(len(filenames))
167 | for i, filename := range filenames {
168 | go func(i int, filepath string) {
169 | defer wg.Done()
170 | src, err := open(filepath)
171 | if err != nil {
172 | errors[i] = err // open provides operation and filename in error
173 | return
174 | }
175 | files[i], errors[i] = parser.ParseFile(p.fset, filepath, src, 0)
176 | src.Close() // ignore Close error - parsing may have succeeded which is all we need
177 | }(i, p.joinPath(dir, filename))
178 | }
179 | wg.Wait()
180 |
181 | // if there are errors, return the first one for deterministic results
182 | for _, err := range errors {
183 | if err != nil {
184 | return nil, err
185 | }
186 | }
187 |
188 | return files, nil
189 | }
190 |
191 | // context-controlled file system operations
192 |
193 | func (p *Importer) absPath(path string) (string, error) {
194 | // TODO(gri) This should be using p.ctxt.AbsPath which doesn't
195 | // exist but probably should. See also issue #14282.
196 | return filepath.Abs(path)
197 | }
198 |
199 | func (p *Importer) isAbsPath(path string) bool {
200 | if f := p.ctxt.IsAbsPath; f != nil {
201 | return f(path)
202 | }
203 | return filepath.IsAbs(path)
204 | }
205 |
206 | func (p *Importer) joinPath(elem ...string) string {
207 | if f := p.ctxt.JoinPath; f != nil {
208 | return f(elem...)
209 | }
210 | return filepath.Join(elem...)
211 | }
212 |
--------------------------------------------------------------------------------
/pkg/command/command.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | //modify 2013-2014 visualfc
6 |
7 | package command
8 |
9 | import (
10 | "bytes"
11 | "flag"
12 | "fmt"
13 | "io"
14 | "log"
15 | "os"
16 | "strings"
17 | "text/template"
18 | "unicode"
19 | "unicode/utf8"
20 | )
21 |
22 | // A Command is an implementation of a go command
23 | // like go build or go fix.
24 | type Command struct {
25 | // Run runs the command.
26 | // The args are the arguments after the command name.
27 | Run func(cmd *Command, args []string) error
28 |
29 | // UsageLine is the one-line usage message.
30 | // The first word in the line is taken to be the command name.
31 | UsageLine string
32 |
33 | // Short is the short description shown in the 'go help' output.
34 | Short string
35 |
36 | // Long is the long message shown in the 'go help ' output.
37 | Long string
38 |
39 | // Flag is a set of flags specific to this command.
40 | Flag flag.FlagSet
41 |
42 | // CustomFlags indicates that the command will do its own
43 | // flag parsing.
44 | CustomFlags bool
45 |
46 | Stdin io.Reader
47 | Stdout io.Writer
48 | Stderr io.Writer
49 | }
50 |
51 | // Name returns the command's name: the first word in the usage line.
52 | func (c *Command) Name() string {
53 | name := c.UsageLine
54 | i := strings.Index(name, " ")
55 | if i >= 0 {
56 | name = name[:i]
57 | }
58 | return name
59 | }
60 |
61 | func (c *Command) Usage() {
62 | fmt.Fprintf(c.Stderr, "usage: %s %s\n", AppName, c.UsageLine)
63 | c.Flag.SetOutput(c.Stderr)
64 | c.Flag.PrintDefaults()
65 | //fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
66 | //os.Exit(2)
67 | }
68 |
69 | func (c *Command) PrintUsage() {
70 | fmt.Fprintf(c.Stderr, "usage: %s %s\n", AppName, c.UsageLine)
71 | c.Flag.SetOutput(c.Stderr)
72 | c.Flag.PrintDefaults()
73 | }
74 |
75 | // Runnable reports whether the command can be run; otherwise
76 | // it is a documentation pseudo-command such as importpath.
77 | func (c *Command) Runnable() bool {
78 | return c.Run != nil
79 | }
80 |
81 | func (c *Command) Println(args ...interface{}) {
82 | fmt.Fprintln(c.Stdout, args...)
83 | }
84 |
85 | func (c *Command) Printf(format string, args ...interface{}) {
86 | fmt.Fprintf(c.Stdout, format, args...)
87 | }
88 |
89 | var commands []*Command
90 |
91 | func Register(cmd *Command) {
92 | commands = append(commands, cmd)
93 | }
94 |
95 | func CommandList() (cmds []string) {
96 | for _, cmd := range commands {
97 | cmds = append(cmds, cmd.Name())
98 | }
99 | return
100 | }
101 |
102 | var (
103 | Stdout io.Writer = os.Stdout
104 | Stderr io.Writer = os.Stderr
105 | Stdin io.Reader = os.Stdin
106 | )
107 |
108 | func RunArgs(arguments []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
109 | flag.CommandLine.VisitAll(func(f *flag.Flag) {
110 | f.Value.Set(f.DefValue)
111 | })
112 | flag.CommandLine.Parse(arguments)
113 | args := flag.Args()
114 | if len(args) < 1 {
115 | printUsage(os.Stderr)
116 | return os.ErrInvalid
117 | }
118 |
119 | if len(args) == 1 && strings.TrimSpace(args[0]) == "" {
120 | printUsage(os.Stderr)
121 | return os.ErrInvalid
122 | }
123 |
124 | if args[0] == "help" {
125 | if !help(args[1:]) {
126 | return os.ErrInvalid
127 | }
128 | return nil
129 | }
130 |
131 | for _, cmd := range commands {
132 | if cmd.Name() == args[0] && cmd.Run != nil {
133 | cmd.Flag.VisitAll(func(f *flag.Flag) {
134 | f.Value.Set(f.DefValue)
135 | })
136 | cmd.Flag.Usage = func() { cmd.Usage() }
137 | cmd.Stdin = stdin
138 | cmd.Stdout = stdout
139 | cmd.Stderr = stderr
140 | if cmd.CustomFlags {
141 | args = args[1:]
142 | } else {
143 | err := cmd.Flag.Parse(args[1:])
144 | if err != nil {
145 | return err
146 | }
147 | args = cmd.Flag.Args()
148 | }
149 | return cmd.Run(cmd, args)
150 | }
151 | }
152 |
153 | fmt.Fprintf(os.Stderr, "%s: unknown subcommand %q\nRun '%s help' for usage.\n",
154 | AppName, args[0], AppName)
155 | return os.ErrInvalid
156 | }
157 |
158 | func Main() {
159 | flag.Usage = func() {
160 | printUsage(os.Stderr)
161 | }
162 | flag.Parse()
163 | log.SetFlags(0)
164 |
165 | args := flag.Args()
166 | if len(args) < 1 {
167 | flag.Usage()
168 | Exit(2)
169 | }
170 |
171 | if len(args) == 1 && strings.TrimSpace(args[0]) == "" {
172 | flag.Usage()
173 | Exit(2)
174 | }
175 |
176 | if args[0] == "help" {
177 | if !help(args[1:]) {
178 | os.Exit(2)
179 | }
180 | return
181 | }
182 |
183 | for _, cmd := range commands {
184 | if cmd.Name() == args[0] && cmd.Run != nil {
185 | cmd.Stdin = Stdin
186 | cmd.Stdout = Stdout
187 | cmd.Stderr = Stderr
188 | if cmd.CustomFlags {
189 | args = args[1:]
190 | } else {
191 | err := cmd.Flag.Parse(args[1:])
192 | if err != nil {
193 | Exit(2)
194 | }
195 | args = cmd.Flag.Args()
196 | }
197 | cmd.Flag.Usage = func() { cmd.Usage() }
198 | err := cmd.Run(cmd, args)
199 | if err != nil {
200 | fmt.Fprintln(cmd.Stderr, err)
201 | Exit(2)
202 | }
203 | Exit(0)
204 | return
205 | }
206 | }
207 |
208 | fmt.Fprintf(os.Stderr, "%s: unknown subcommand %q\nRun '%s help' for usage.\n",
209 | AppName, args[0], AppName)
210 | Exit(2)
211 | }
212 |
213 | var AppInfo string = "LiteIDE golang tool."
214 | var AppName string = "tools"
215 |
216 | var usageTemplate = `
217 | Usage:
218 |
219 | {{AppName}} command [arguments]
220 |
221 | The commands are:
222 | {{range .}}{{if .Runnable}}
223 | {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
224 |
225 | Use "{{AppName}} help [command]" for more information about a command.
226 |
227 | Additional help topics:
228 | {{range .}}{{if not .Runnable}}
229 | {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
230 |
231 | Use "{{AppName}} help [topic]" for more information about that topic.
232 |
233 | `
234 |
235 | var helpTemplate = `{{if .Runnable}}usage: {{AppName}} {{.UsageLine}}
236 |
237 | {{end}}{{.Long | trim}}
238 | `
239 |
240 | var documentationTemplate = `//
241 | /*
242 | {{range .}}{{if .Short}}{{.Short | capitalize}}
243 |
244 | {{end}}{{if .Runnable}}Usage:
245 |
246 | {{AppName}} {{.UsageLine}}
247 |
248 | {{end}}{{.Long | trim}}
249 |
250 |
251 | {{end}}*/
252 | package main
253 | `
254 |
255 | // tmpl executes the given template text on data, writing the result to w.
256 | func tmpl(w io.Writer, text string, data interface{}) {
257 | t := template.New("top")
258 | t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
259 | template.Must(t.Parse(text))
260 | if err := t.Execute(w, data); err != nil {
261 | panic(err)
262 | }
263 | }
264 |
265 | func capitalize(s string) string {
266 | if s == "" {
267 | return s
268 | }
269 | r, n := utf8.DecodeRuneInString(s)
270 | return string(unicode.ToTitle(r)) + s[n:]
271 | }
272 |
273 | func printUsage(w io.Writer) {
274 | if len(AppInfo) > 0 {
275 | fmt.Fprintln(w, AppInfo)
276 | }
277 | tmpl(w, strings.Replace(usageTemplate, "{{AppName}}", AppName, -1), commands)
278 | }
279 |
280 | // help implements the 'help' command.
281 | func help(args []string) bool {
282 | if len(args) == 0 {
283 | printUsage(os.Stdout)
284 | // not exit 2: succeeded at 'go help'.
285 | return true
286 | }
287 | if len(args) != 1 {
288 | fmt.Fprintf(os.Stderr, "usage: %s help command\n\nToo many arguments given.\n", AppName)
289 | return false
290 | }
291 |
292 | arg := args[0]
293 |
294 | // 'go help documentation' generates doc.go.
295 | if arg == "documentation" {
296 | buf := new(bytes.Buffer)
297 | printUsage(buf)
298 | usage := &Command{Long: buf.String()}
299 | tmpl(os.Stdout, strings.Replace(documentationTemplate, "{{AppName}}", AppName, -1), append([]*Command{usage}, commands...))
300 | return false
301 | }
302 |
303 | for _, cmd := range commands {
304 | if cmd.Name() == arg {
305 | tmpl(os.Stdout, strings.Replace(helpTemplate, "{{AppName}}", AppName, -1), cmd)
306 | // not exit 2: succeeded at 'go help cmd'.
307 | return true
308 | }
309 | }
310 |
311 | fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run '%s help'.\n", arg, AppName)
312 | return false
313 | }
314 |
315 | func Exit(code int) {
316 | os.Exit(code)
317 | }
318 |
--------------------------------------------------------------------------------
/pkg/pkgutil/pkgutil.go:
--------------------------------------------------------------------------------
1 | package pkgutil
2 |
3 | import (
4 | "fmt"
5 | "go/build"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "regexp"
10 | "strings"
11 | )
12 |
13 | //var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"
14 |
15 | func IsVendorExperiment() bool {
16 | return true
17 | }
18 |
19 | // matchPattern(pattern)(name) reports whether
20 | // name matches pattern. Pattern is a limited glob
21 | // pattern in which '...' means 'any string' and there
22 | // is no other special syntax.
23 | func matchPattern(pattern string) func(name string) bool {
24 | re := regexp.QuoteMeta(pattern)
25 | re = strings.Replace(re, `\.\.\.`, `.*`, -1)
26 | // Special case: foo/... matches foo too.
27 | if strings.HasSuffix(re, `/.*`) {
28 | re = re[:len(re)-len(`/.*`)] + `(/.*)?`
29 | }
30 | reg := regexp.MustCompile(`^` + re + `$`)
31 | return func(name string) bool {
32 | return reg.MatchString(name)
33 | }
34 | }
35 |
36 | // hasPathPrefix reports whether the path s begins with the
37 | // elements in prefix.
38 | func hasPathPrefix(s, prefix string) bool {
39 | switch {
40 | default:
41 | return false
42 | case len(s) == len(prefix):
43 | return s == prefix
44 | case len(s) > len(prefix):
45 | if prefix != "" && prefix[len(prefix)-1] == '/' {
46 | return strings.HasPrefix(s, prefix)
47 | }
48 | return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
49 | }
50 | }
51 |
52 | // hasFilePathPrefix reports whether the filesystem path s begins with the
53 | // elements in prefix.
54 | func hasFilePathPrefix(s, prefix string) bool {
55 | sv := strings.ToUpper(filepath.VolumeName(s))
56 | pv := strings.ToUpper(filepath.VolumeName(prefix))
57 | s = s[len(sv):]
58 | prefix = prefix[len(pv):]
59 | switch {
60 | default:
61 | return false
62 | case sv != pv:
63 | return false
64 | case len(s) == len(prefix):
65 | return s == prefix
66 | case len(s) > len(prefix):
67 | if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
68 | return strings.HasPrefix(s, prefix)
69 | }
70 | return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
71 | }
72 | }
73 |
74 | // treeCanMatchPattern(pattern)(name) reports whether
75 | // name or children of name can possibly match pattern.
76 | // Pattern is the same limited glob accepted by matchPattern.
77 | func treeCanMatchPattern(pattern string) func(name string) bool {
78 | wildCard := false
79 | if i := strings.Index(pattern, "..."); i >= 0 {
80 | wildCard = true
81 | pattern = pattern[:i]
82 | }
83 | return func(name string) bool {
84 | return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
85 | wildCard && strings.HasPrefix(name, pattern)
86 | }
87 | }
88 |
89 | var isDirCache = map[string]bool{}
90 |
91 | func isDir(path string) bool {
92 | result, ok := isDirCache[path]
93 | if ok {
94 | return result
95 | }
96 |
97 | fi, err := os.Stat(path)
98 | result = err == nil && fi.IsDir()
99 | isDirCache[path] = result
100 | return result
101 | }
102 |
103 | type Package struct {
104 | Root string
105 | Dir string
106 | ImportPath string
107 | }
108 |
109 | func ImportFile(fileName string) *Package {
110 | return ImportDir(filepath.Dir(fileName))
111 | }
112 |
113 | func ImportDir(dir string) *Package {
114 | pkg, err := build.ImportDir(dir, build.FindOnly)
115 | if err != nil {
116 | return &Package{"", dir, ""}
117 | }
118 | return &Package{pkg.Root, pkg.Dir, pkg.ImportPath}
119 | }
120 |
121 | func ImportDirEx(ctx *build.Context, dir string) *Package {
122 | pkg, err := ctx.ImportDir(dir, build.FindOnly)
123 | if err != nil {
124 | return &Package{"", dir, ""}
125 | }
126 | return &Package{pkg.Root, pkg.Dir, pkg.ImportPath}
127 | }
128 |
129 | // expandPath returns the symlink-expanded form of path.
130 | func expandPath(p string) string {
131 | x, err := filepath.EvalSymlinks(p)
132 | if err == nil {
133 | return x
134 | }
135 | return p
136 | }
137 |
138 | // vendoredImportPath returns the expansion of path when it appears in parent.
139 | // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
140 | // x/vendor/path, vendor/path, or else stay path if none of those exist.
141 | // vendoredImportPath returns the expanded path or, if no expansion is found, the original.
142 | func VendoredImportPath(parent *Package, path string) (found string, err error) {
143 | if parent == nil || parent.Root == "" {
144 | return path, nil
145 | }
146 |
147 | dir := filepath.Clean(parent.Dir)
148 | root := filepath.Join(parent.Root, "src")
149 | if !hasFilePathPrefix(dir, root) {
150 | // Look for symlinks before reporting error.
151 | dir = expandPath(dir)
152 | root = expandPath(root)
153 | }
154 | if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {
155 | return "", fmt.Errorf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
156 | }
157 |
158 | vpath := "vendor/" + path
159 | for i := len(dir); i >= len(root); i-- {
160 | if i < len(dir) && dir[i] != filepath.Separator {
161 | continue
162 | }
163 | // Note: checking for the vendor directory before checking
164 | // for the vendor/path directory helps us hit the
165 | // isDir cache more often. It also helps us prepare a more useful
166 | // list of places we looked, to report when an import is not found.
167 | if !isDir(filepath.Join(dir[:i], "vendor")) {
168 | continue
169 | }
170 | targ := filepath.Join(dir[:i], vpath)
171 | if isDir(targ) && hasGoFiles(targ) {
172 | importPath := parent.ImportPath
173 | if importPath == "command-line-arguments" {
174 | // If parent.ImportPath is 'command-line-arguments'.
175 | // set to relative directory to root (also chopped root directory)
176 | importPath = dir[len(root)+1:]
177 | }
178 | // We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
179 | // We know the import path for parent's dir.
180 | // We chopped off some number of path elements and
181 | // added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.
182 | // Now we want to know the import path for that directory.
183 | // Construct it by chopping the same number of path elements
184 | // (actually the same number of bytes) from parent's import path
185 | // and then append /vendor/path.
186 | chopped := len(dir) - i
187 | if chopped == len(importPath)+1 {
188 | // We walked up from c:\gopath\src\foo\bar
189 | // and found c:\gopath\src\vendor\path.
190 | // We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
191 | // Use "vendor/path" without any prefix.
192 | return vpath, nil
193 | }
194 | return importPath[:len(importPath)-chopped] + "/" + vpath, nil
195 | }
196 | }
197 | return path, nil
198 | }
199 |
200 | // hasGoFiles reports whether dir contains any files with names ending in .go.
201 | // For a vendor check we must exclude directories that contain no .go files.
202 | // Otherwise it is not possible to vendor just a/b/c and still import the
203 | // non-vendored a/b. See golang.org/issue/13832.
204 | func hasGoFiles(dir string) bool {
205 | fis, _ := ioutil.ReadDir(dir)
206 | for _, fi := range fis {
207 | if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
208 | return true
209 | }
210 | }
211 | return false
212 | }
213 |
214 | // findVendor looks for the last non-terminating "vendor" path element in the given import path.
215 | // If there isn't one, findVendor returns ok=false.
216 | // Otherwise, findVendor returns ok=true and the index of the "vendor".
217 | //
218 | // Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
219 | // not the vendored copy of an import "" (the empty import path).
220 | // This will allow people to have packages or commands named vendor.
221 | // This may help reduce breakage, or it may just be confusing. We'll see.
222 | func findVendor(path string) (index int, ok bool) {
223 | // Two cases, depending on internal at start of string or not.
224 | // The order matters: we must return the index of the final element,
225 | // because the final one is where the effective import path starts.
226 | switch {
227 | case strings.Contains(path, "/vendor/"):
228 | return strings.LastIndex(path, "/vendor/") + 1, true
229 | case strings.HasPrefix(path, "vendor/"):
230 | return 0, true
231 | }
232 | return 0, false
233 | }
234 |
235 | func VendorPathToImportPath(path string) string {
236 | if i, ok := findVendor(path); ok {
237 | return path[i+len("vendor/"):]
238 | }
239 | return path
240 | }
241 |
--------------------------------------------------------------------------------
/docview/docview.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package docview
6 |
7 | import (
8 | "bytes"
9 | "fmt"
10 | "go/build"
11 | "log"
12 | "os"
13 | "path/filepath"
14 | "runtime"
15 | "strings"
16 | "text/template"
17 |
18 | "github.com/visualfc/gotools/pkg/command"
19 | )
20 |
21 | var Command = &command.Command{
22 | Run: runDocView,
23 | UsageLine: "docview [-mode] [-list|-find]",
24 | Short: "golang docview util",
25 | Long: `golang docview util`,
26 | }
27 |
28 | var goroot = runtime.GOROOT()
29 |
30 | var docViewFind string
31 | var docViewList string
32 | var docViewMode string
33 |
34 | func init() {
35 | Command.Flag.StringVar(&docViewFind, "find", "", "find package list, :pkg flag is best match")
36 | Command.Flag.StringVar(&docViewList, "list", "", "Print go packages list [pkg|cmd]")
37 | Command.Flag.StringVar(&docViewMode, "mode", "text", "Print mode [text|html|lite]")
38 | }
39 |
40 | func runDocView(cmd *command.Command, args []string) error {
41 | if docViewFind == "" && docViewList == "" {
42 | cmd.Usage()
43 | return os.ErrInvalid
44 | }
45 |
46 | var template string
47 | var info *Info
48 | if len(docViewList) > 0 {
49 | pkgPath := filepath.Join(goroot, "src", docViewList)
50 | if docViewList == "pkg" {
51 | _, err := os.Stat(pkgPath)
52 | if err != nil {
53 | pkgPath = filepath.Join(goroot, "src")
54 | }
55 | }
56 | info = NewListInfo(pkgPath)
57 | if info != nil {
58 | if docViewList == "pkg" {
59 | var filterList []DirEntry
60 | for _, v := range info.Dirs.List {
61 | if v.Path == "cmd" {
62 | continue
63 | }
64 | if strings.HasPrefix(v.Path, "cmd/") {
65 | continue
66 | }
67 | if strings.Contains(v.Path, "/testdata") {
68 | continue
69 | }
70 | filterList = append(filterList, v)
71 | }
72 | info.Dirs.List = filterList
73 | } else if docViewList == "cmd" {
74 | var filterList []DirEntry
75 | for _, v := range info.Dirs.List {
76 | if strings.Contains(v.Path, "/") {
77 | continue
78 | }
79 | if strings.Contains(v.Path, "internal") {
80 | continue
81 | }
82 | filterList = append(filterList, v)
83 | }
84 | info.Dirs.List = filterList
85 | }
86 | }
87 | switch docViewMode {
88 | case "html":
89 | template = listHTML
90 | case "lite":
91 | template = listLite
92 | case "text":
93 | template = listText
94 | default:
95 | template = listText
96 | }
97 | } else if len(docViewFind) > 0 {
98 | dir := NewSourceDir(goroot)
99 | info = dir.FindInfo(docViewFind)
100 | switch docViewMode {
101 | case "html":
102 | template = findHTML
103 | case "lite":
104 | template = findLite
105 | case "text":
106 | template = findText
107 | default:
108 | template = findText
109 | }
110 | }
111 | if info == nil {
112 | return os.ErrNotExist
113 | }
114 | contents := info.GetPkgList(docViewMode, template)
115 | fmt.Fprintf(cmd.Stdout, "%s", contents)
116 | return nil
117 | }
118 |
119 | var (
120 | fs FileSystem = OS // the underlying file system
121 | )
122 |
123 | // Fake package file and name for commands. Contains the command documentation.
124 | const fakePkgName = "documentation"
125 |
126 | var fmap = template.FuncMap{
127 | "repeat": strings.Repeat,
128 | }
129 |
130 | func readTemplateData(name, data string) *template.Template {
131 | return template.Must(template.New(name).Funcs(fmap).Parse(data))
132 | }
133 |
134 | func readTemplateFile(name, path string) *template.Template {
135 | return template.Must(template.New(name).Funcs(fmap).ParseFiles(path))
136 | }
137 |
138 | func applyTemplate(t *template.Template, name string, data interface{}) []byte {
139 | var buf bytes.Buffer
140 | if err := t.Execute(&buf, data); err != nil {
141 | log.Printf("%s.Execute: %s", name, err)
142 | }
143 | return buf.Bytes()
144 | }
145 |
146 | type Info struct {
147 | Find string
148 | Best *DirEntry
149 | Dirs *DirList
150 | }
151 |
152 | type GodocDir struct {
153 | pkg *Directory
154 | cmd *Directory
155 | gopath []*Directory
156 | }
157 |
158 | func NewSourceDir(goroot string) *GodocDir {
159 | pkgPath := filepath.Join(goroot, "src/pkg")
160 | _, err := os.Stat(pkgPath)
161 | var cmd *Directory
162 | if err != nil {
163 | pkgPath = filepath.Join(goroot, "src")
164 | } else {
165 | cmd = newDirectory(filepath.Join(goroot, "src", "cmd"), nil, -1)
166 | }
167 | pkg := newDirectory(pkgPath, nil, -1)
168 | ctx := build.Default
169 | ctx.GOROOT = ""
170 | var gopath []*Directory
171 | for _, v := range ctx.SrcDirs() {
172 | gopath = append(gopath, newDirectory(v, nil, -1))
173 | }
174 | return &GodocDir{pkg, cmd, gopath}
175 | }
176 |
177 | func (dir *GodocDir) FindInfo(name string) *Info {
178 | max1, best1, list1 := FindDir(dir.pkg, name)
179 | max2, best2, list2 := FindDir(dir.cmd, name)
180 | var maxHeight int
181 | if max1 >= max2 {
182 | maxHeight = max1
183 | } else {
184 | maxHeight = max2
185 | }
186 | var best *DirEntry
187 | if best1 != nil {
188 | best = best1
189 | if best2 != nil {
190 | list2 = append(list2, *best2)
191 | }
192 | } else {
193 | best = best2
194 | }
195 | var list []DirEntry
196 | list = append(list, list1...)
197 | list = append(list, list2...)
198 | for _, v := range dir.gopath {
199 | max3, best3, list3 := FindDir(v, name)
200 | if max3 > maxHeight {
201 | maxHeight = max3
202 | }
203 | if best == nil {
204 | best = best3
205 | }
206 | list = append(list, list3...)
207 | }
208 | return &Info{name, best, &DirList{maxHeight, list}}
209 | }
210 |
211 | func FindDir(dir *Directory, pkgname string) (maxHeight int, best *DirEntry, list []DirEntry) {
212 | if dir == nil {
213 | return
214 | }
215 | dirList := dir.listing(true)
216 | max := len(dirList.List)
217 | maxHeight = dirList.MaxHeight
218 |
219 | for i := 0; i < max; i++ {
220 | name := dirList.List[i].Name
221 | path := filepath.ToSlash(dirList.List[i].Path)
222 | if name == pkgname || path == pkgname {
223 | best = &dirList.List[i]
224 | } else if strings.Contains(path, pkgname) {
225 | list = append(list, dirList.List[i])
226 | }
227 | }
228 | return
229 | }
230 |
231 | func appendList(list1, list2 []DirEntry) []DirEntry {
232 | list := list1
233 | max := len(list2)
234 | for i := 0; i < max; i++ {
235 | list = append(list, list2[i])
236 | }
237 | return list
238 | }
239 |
240 | func NewListInfo(root string) *Info {
241 | dir := newDirectory(root, nil, -1)
242 | if dir == nil {
243 | return nil
244 | }
245 | return &Info{"", nil, dir.listing(true)}
246 | }
247 |
248 | func FindPkgInfo(root string, pkgname string) *Info {
249 | dir := newDirectory(root, nil, -1)
250 | if dir == nil {
251 | return nil
252 | }
253 | dirList := dir.listing(true)
254 | if pkgname == "*" {
255 | return &Info{pkgname, nil, dirList}
256 | }
257 | var best DirEntry
258 | var list []DirEntry
259 | max := len(dirList.List)
260 | for i := 0; i < max; i++ {
261 | name := dirList.List[i].Name
262 | path := filepath.ToSlash(dirList.List[i].Path)
263 | if name == pkgname || path == pkgname {
264 | best = dirList.List[i]
265 | } else if strings.Contains(path, pkgname) {
266 | list = append(list, dirList.List[i])
267 | }
268 | }
269 | return &Info{pkgname, &best, &DirList{dirList.MaxHeight, list}}
270 | }
271 |
272 | func (info *Info) GetPkgList(name, templateData string) []byte {
273 | data := readTemplateData(name, templateData)
274 | return applyTemplate(data, "pkglist", info)
275 | }
276 |
277 | var listHTML = `
278 |
279 | Need more packages? The
280 | Package Dashboard
281 | provides a list of goinstallable packages.
282 |
283 | Subdirectories
284 |
285 | {{with .Dirs}}
286 |
287 |
288 |
289 | Name
290 |
291 | Synopsis
292 |
293 | {{range .List}}
294 |
295 | {{repeat " " .Depth}}
296 | {{html .Name}}
297 |
298 | {{html .Synopsis}}
299 |
300 | {{end}}
301 |
302 |
303 | {{end}}`
304 |
305 | var listText = `$list
306 | {{with .Dirs}}
307 | {{range .List}}{{.Path }}
308 | {{end}}
309 | {{end}}`
310 |
311 | var listLite = `$list{{with .Dirs}}{{range .List}},{{.Path}}{{end}}{{end}}`
312 |
313 | var findHTML = `
314 |
315 | Need more packages? The
316 | Package Dashboard
317 | provides a list of goinstallable packages.
318 |
319 | Subdirectories
320 |
321 |
322 | Best
323 |
324 | Synopsis
325 | {{with .Best}}
326 |
327 | {{.Path}}
328 |
329 | {{html .Synopsis}}
330 |
331 | {{end}}
332 | {{with .Dirs}}
333 |
334 | Match
335 |
336 | Synopsis
337 |
338 | {{range .List}}
339 |
340 | {{.Path}}
341 |
342 | {{html .Synopsis}}
343 |
344 | {{end}}
345 |
346 |
347 | {{end}}`
348 |
349 | var findText = `$best
350 | {{with .Best}}{{.Path}}{{end}}
351 | $list
352 | {{with .Dirs}}{{range .List}}{{.Path}}
353 | {{end}}{{end}}`
354 |
355 | var findLite = `$find,{{with .Best}}{{.Path}}{{end}}{{with .Dirs}}{{range .List}},{{.Path}}{{end}}{{end}}`
356 |
--------------------------------------------------------------------------------
/gopresent/gopresent.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | //modify 2013-2014 visualfc
6 |
7 | package gopresent
8 |
9 | import (
10 | "fmt"
11 | "html/template"
12 | "io"
13 | "os"
14 | "path/filepath"
15 |
16 | "github.com/visualfc/gotools/pkg/command"
17 | "golang.org/x/tools/present"
18 | )
19 |
20 | var Command = &command.Command{
21 | Run: runPresent,
22 | UsageLine: "gopresent",
23 | Short: "golang present util",
24 | Long: `golang present util`,
25 | }
26 |
27 | var presentVerifyOnly bool
28 | var presentInput string
29 | var presentStdout bool
30 | var presentOutput string
31 |
32 | func init() {
33 | Command.Flag.BoolVar(&presentVerifyOnly, "v", false, "verify present only")
34 | Command.Flag.BoolVar(&presentStdout, "stdout", false, "output use std output")
35 | Command.Flag.StringVar(&presentInput, "i", "", "input golang present file")
36 | Command.Flag.StringVar(&presentOutput, "o", "", "output html file name")
37 | }
38 |
39 | func runPresent(cmd *command.Command, args []string) error {
40 | if presentInput == "" || !isDoc(presentInput) {
41 | cmd.Usage()
42 | return os.ErrInvalid
43 | }
44 |
45 | if presentVerifyOnly {
46 | err := VerifyDoc(presentInput)
47 | if err != nil {
48 | return err
49 | }
50 | return nil
51 | }
52 | w := cmd.Stdout
53 | if !presentStdout {
54 | if presentOutput == "" {
55 | presentOutput = presentInput + ".html"
56 | }
57 | ext := filepath.Ext(presentOutput)
58 | if ext != ".htm" && ext != ".html" {
59 | presentOutput += ".html"
60 | }
61 | var err error
62 | w, err = os.Create(presentOutput)
63 | if err != nil {
64 | return err
65 | }
66 | }
67 | err := RenderDoc(w, presentInput)
68 | return err
69 | }
70 |
71 | var extensions = map[string]string{
72 | ".slide": "slides.tmpl",
73 | ".article": "article.tmpl",
74 | }
75 |
76 | var extensions_tmpl = map[string]string{
77 | ".slide": slides_tmpl,
78 | ".article": article_tmpl,
79 | }
80 |
81 | func isDoc(path string) bool {
82 | _, ok := extensions[filepath.Ext(path)]
83 | return ok
84 | }
85 |
86 | func VerifyDoc(docFile string) error {
87 | doc, err := parse(docFile, 0)
88 | if err != nil {
89 | return err
90 | }
91 | dir := filepath.Dir(docFile)
92 | return verify_doc(dir, doc)
93 | }
94 |
95 | // renderDoc reads the present file, builds its template representation,
96 | // and executes the template, sending output to w.
97 | func renderDoc(w io.Writer, base, docFile string) error {
98 | // Read the input and build the doc structure.
99 | doc, err := parse(docFile, 0)
100 | if err != nil {
101 | return err
102 | }
103 |
104 | // Find which template should be executed.
105 | ext := filepath.Ext(docFile)
106 | contentTmpl, ok := extensions[ext]
107 | if !ok {
108 | return fmt.Errorf("no template for extension %v", ext)
109 | }
110 |
111 | // Locate the template file.
112 | actionTmpl := filepath.Join(base, "templates/action.tmpl")
113 | contentTmpl = filepath.Join(base, "templates", contentTmpl)
114 |
115 | // Read and parse the input.
116 | tmpl := present.Template()
117 | tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
118 | if _, err := tmpl.ParseFiles(actionTmpl, contentTmpl); err != nil {
119 | return err
120 | }
121 | // Execute the template.
122 | return doc.Render(w, tmpl)
123 | }
124 |
125 | func RenderDoc(w io.Writer, docFile string) error {
126 | // Read the input and build the doc structure.
127 | doc, err := parse(docFile, 0)
128 | if err != nil {
129 | return err
130 | }
131 |
132 | // Find which template should be executed.
133 | ext := filepath.Ext(docFile)
134 | contentTmpl, ok := extensions_tmpl[ext]
135 | if !ok {
136 | return fmt.Errorf("no template for extension %v", ext)
137 | }
138 |
139 | // Locate the template file.
140 | actionTmpl := action_tmpl //filepath.Join(base, "templates/action.tmpl")
141 | // Read and parse the input.
142 | tmpl := present.Template()
143 | tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
144 | if tmpl, err = tmpl.New("action").Parse(actionTmpl); err != nil {
145 | return err
146 | }
147 | if tmpl, err = tmpl.New("content").Parse(contentTmpl); err != nil {
148 | return err
149 | }
150 |
151 | // Execute the template.
152 | return doc.Render(w, tmpl)
153 | }
154 |
155 | func parse(name string, mode present.ParseMode) (*present.Doc, error) {
156 | f, err := os.Open(name)
157 | if err != nil {
158 | return nil, err
159 | }
160 | defer f.Close()
161 | return present.Parse(f, name, 0)
162 | }
163 |
164 | func playable(c present.Code) bool {
165 | return present.PlayEnabled && c.Play
166 | }
167 |
168 | func isSkipURL(url string) bool {
169 | if filepath.HasPrefix(url, "http://") {
170 | return true
171 | }
172 | if filepath.HasPrefix(url, "https://") {
173 | return true
174 | }
175 | return false
176 | }
177 |
178 | func verify_path(root string, url string) error {
179 | if isSkipURL(url) {
180 | return nil
181 | }
182 | path := url
183 | if !filepath.IsAbs(url) {
184 | path = filepath.Join(root, path)
185 | }
186 | _, err := os.Stat(path)
187 | if err != nil {
188 | return err
189 | }
190 | return nil
191 | }
192 |
193 | func verify_doc(root string, doc *present.Doc) error {
194 | for _, section := range doc.Sections {
195 | for _, elem := range section.Elem {
196 | switch i := elem.(type) {
197 | case present.Image:
198 | if err := verify_path(root, i.URL); err != nil {
199 | return fmt.Errorf("! .image %s not exist", i.URL)
200 | }
201 | }
202 | }
203 | }
204 | return nil
205 | }
206 |
207 | var action_tmpl = `
208 | {/*
209 | This is the action template.
210 | It determines how the formatting actions are rendered.
211 | */}
212 |
213 | {{define "section"}}
214 | {{.FormattedNumber}} {{.Title}}
215 | {{range .Elem}}{{elem $.Template .}}{{end}}
216 | {{end}}
217 |
218 | {{define "list"}}
219 |
220 | {{range .Bullet}}
221 | {{style .}}
222 | {{end}}
223 |
224 | {{end}}
225 |
226 | {{define "text"}}
227 | {{if .Pre}}
228 | {{range .Lines}}{{.}}{{end}}
229 | {{else}}
230 |
231 | {{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}
232 | {{end}}{{style $l}}{{end}}
233 |
234 | {{end}}
235 | {{end}}
236 |
237 | {{define "code"}}
238 | {{.Text}}
239 | {{end}}
240 |
241 | {{define "image"}}
242 |
243 |
244 |
245 | {{end}}
246 |
247 | {{define "iframe"}}
248 |
249 | {{end}}
250 |
251 | {{define "link"}}{{style .Label}}
{{end}}
252 |
253 | {{define "html"}}{{.HTML}}{{end}}
254 | `
255 |
256 | var article_tmpl = `
257 | {/* This is the article template. It defines how articles are formatted. */}
258 |
259 | {{define "root"}}
260 |
261 |
262 |
263 | {{.Title}}
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
{{.Title}}
272 | {{with .Subtitle}}{{.}}{{end}}
273 |
274 |
275 |
276 |
277 |
278 | {{with .Sections}}
279 |
280 | {{template "TOC" .}}
281 |
282 | {{end}}
283 |
284 | {{range .Sections}}
285 | {{elem $.Template .}}
286 | {{end}}{{/* of Section block */}}
287 |
288 |
Authors
289 | {{range .Authors}}
290 |
291 | {{range .Elem}}{{elem $.Template .}}{{end}}
292 |
293 | {{end}}
294 |
295 |
296 |
297 |
298 |
299 | {{end}}
300 |
301 | {{define "TOC"}}
302 |
303 | {{range .}}
304 | {{.Title}}
305 | {{with .Sections}}{{template "TOC" .}}{{end}}
306 | {{end}}
307 |
308 | {{end}}
309 |
310 | {{define "newline"}}
311 | {{/* No automatic line break. Paragraphs are free-form. */}}
312 | {{end}}
313 | `
314 |
315 | var slides_tmpl = `
316 | {/* This is the slide template. It defines how presentations are formatted. */}
317 |
318 | {{define "root"}}
319 |
320 |
321 |
322 | {{.Title}}
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 | {{.Title}}
333 | {{with .Subtitle}}{{.}} {{end}}
334 | {{if not .Time.IsZero}}{{.Time.Format "2 January 2006"}} {{end}}
335 | {{range .Authors}}
336 |
337 | {{range .TextElem}}{{elem $.Template .}}{{end}}
338 |
339 | {{end}}
340 |
341 |
342 | {{range $i, $s := .Sections}}
343 |
344 |
345 | {{if $s.Elem}}
346 | {{$s.Title}}
347 | {{range $s.Elem}}{{elem $.Template .}}{{end}}
348 | {{else}}
349 | {{$s.Title}}
350 | {{end}}
351 |
352 |
353 | {{end}}{{/* of Slide block */}}
354 |
355 |
356 | Thank you
357 | {{range .Authors}}
358 |
359 | {{range .Elem}}{{elem $.Template .}}{{end}}
360 |
361 | {{end}}
362 |
363 |
364 |
365 | {{if .PlayEnabled}}
366 |
367 | {{end}}
368 |
369 | {{end}}
370 |
371 | {{define "newline"}}
372 |
373 | {{end}}
374 | `
375 |
--------------------------------------------------------------------------------
/gopresent/static/styles.css:
--------------------------------------------------------------------------------
1 | /* Framework */
2 |
3 | html {
4 | height: 100%;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | padding: 0;
10 |
11 | display: block !important;
12 |
13 | height: 100%;
14 | min-height: 740px;
15 |
16 | overflow-x: hidden;
17 | overflow-y: auto;
18 |
19 | background: rgb(215, 215, 215);
20 | background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
21 | background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
22 | background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
23 | background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190)));
24 |
25 | -webkit-font-smoothing: antialiased;
26 | }
27 |
28 | .slides {
29 | width: 100%;
30 | height: 100%;
31 | left: 0;
32 | top: 0;
33 |
34 | position: absolute;
35 |
36 | -webkit-transform: translate3d(0, 0, 0);
37 | }
38 |
39 | .slides > article {
40 | display: block;
41 |
42 | position: absolute;
43 | overflow: hidden;
44 |
45 | width: 900px;
46 | height: 700px;
47 |
48 | left: 50%;
49 | top: 50%;
50 |
51 | margin-left: -450px;
52 | margin-top: -350px;
53 |
54 | padding: 40px 60px;
55 |
56 | box-sizing: border-box;
57 | -o-box-sizing: border-box;
58 | -moz-box-sizing: border-box;
59 | -webkit-box-sizing: border-box;
60 |
61 | border-radius: 10px;
62 | -o-border-radius: 10px;
63 | -moz-border-radius: 10px;
64 | -webkit-border-radius: 10px;
65 |
66 | background-color: white;
67 |
68 | border: 1px solid rgba(0, 0, 0, .3);
69 |
70 | transition: transform .3s ease-out;
71 | -o-transition: -o-transform .3s ease-out;
72 | -moz-transition: -moz-transform .3s ease-out;
73 | -webkit-transition: -webkit-transform .3s ease-out;
74 | }
75 | .slides.layout-widescreen > article {
76 | margin-left: -550px;
77 | width: 1100px;
78 | }
79 | .slides.layout-faux-widescreen > article {
80 | margin-left: -550px;
81 | width: 1100px;
82 |
83 | padding: 40px 160px;
84 | }
85 |
86 | .slides.layout-widescreen > article:not(.nobackground):not(.biglogo),
87 | .slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) {
88 | background-position-x: 0, 840px;
89 | }
90 |
91 | /* Clickable/tappable areas */
92 |
93 | .slide-area {
94 | z-index: 1000;
95 |
96 | position: absolute;
97 | left: 0;
98 | top: 0;
99 | width: 150px;
100 | height: 700px;
101 |
102 | left: 50%;
103 | top: 50%;
104 |
105 | cursor: pointer;
106 | margin-top: -350px;
107 |
108 | tap-highlight-color: transparent;
109 | -o-tap-highlight-color: transparent;
110 | -moz-tap-highlight-color: transparent;
111 | -webkit-tap-highlight-color: transparent;
112 | }
113 | #prev-slide-area {
114 | margin-left: -550px;
115 | }
116 | #next-slide-area {
117 | margin-left: 400px;
118 | }
119 | .slides.layout-widescreen #prev-slide-area,
120 | .slides.layout-faux-widescreen #prev-slide-area {
121 | margin-left: -650px;
122 | }
123 | .slides.layout-widescreen #next-slide-area,
124 | .slides.layout-faux-widescreen #next-slide-area {
125 | margin-left: 500px;
126 | }
127 |
128 | /* Slides */
129 |
130 | .slides > article {
131 | display: none;
132 | }
133 | .slides > article.far-past {
134 | display: block;
135 | transform: translate(-2040px);
136 | -o-transform: translate(-2040px);
137 | -moz-transform: translate(-2040px);
138 | -webkit-transform: translate3d(-2040px, 0, 0);
139 | }
140 | .slides > article.past {
141 | display: block;
142 | transform: translate(-1020px);
143 | -o-transform: translate(-1020px);
144 | -moz-transform: translate(-1020px);
145 | -webkit-transform: translate3d(-1020px, 0, 0);
146 | }
147 | .slides > article.current {
148 | display: block;
149 | transform: translate(0);
150 | -o-transform: translate(0);
151 | -moz-transform: translate(0);
152 | -webkit-transform: translate3d(0, 0, 0);
153 | }
154 | .slides > article.next {
155 | display: block;
156 | transform: translate(1020px);
157 | -o-transform: translate(1020px);
158 | -moz-transform: translate(1020px);
159 | -webkit-transform: translate3d(1020px, 0, 0);
160 | }
161 | .slides > article.far-next {
162 | display: block;
163 | transform: translate(2040px);
164 | -o-transform: translate(2040px);
165 | -moz-transform: translate(2040px);
166 | -webkit-transform: translate3d(2040px, 0, 0);
167 | }
168 |
169 | .slides.layout-widescreen > article.far-past,
170 | .slides.layout-faux-widescreen > article.far-past {
171 | display: block;
172 | transform: translate(-2260px);
173 | -o-transform: translate(-2260px);
174 | -moz-transform: translate(-2260px);
175 | -webkit-transform: translate3d(-2260px, 0, 0);
176 | }
177 | .slides.layout-widescreen > article.past,
178 | .slides.layout-faux-widescreen > article.past {
179 | display: block;
180 | transform: translate(-1130px);
181 | -o-transform: translate(-1130px);
182 | -moz-transform: translate(-1130px);
183 | -webkit-transform: translate3d(-1130px, 0, 0);
184 | }
185 | .slides.layout-widescreen > article.current,
186 | .slides.layout-faux-widescreen > article.current {
187 | display: block;
188 | transform: translate(0);
189 | -o-transform: translate(0);
190 | -moz-transform: translate(0);
191 | -webkit-transform: translate3d(0, 0, 0);
192 | }
193 | .slides.layout-widescreen > article.next,
194 | .slides.layout-faux-widescreen > article.next {
195 | display: block;
196 | transform: translate(1130px);
197 | -o-transform: translate(1130px);
198 | -moz-transform: translate(1130px);
199 | -webkit-transform: translate3d(1130px, 0, 0);
200 | }
201 | .slides.layout-widescreen > article.far-next,
202 | .slides.layout-faux-widescreen > article.far-next {
203 | display: block;
204 | transform: translate(2260px);
205 | -o-transform: translate(2260px);
206 | -moz-transform: translate(2260px);
207 | -webkit-transform: translate3d(2260px, 0, 0);
208 | }
209 |
210 | /* Styles for slides */
211 |
212 | .slides > article {
213 | font-family: 'Open Sans', Arial, sans-serif;
214 |
215 | color: black;
216 | text-shadow: 0 1px 1px rgba(0, 0, 0, .1);
217 |
218 | font-size: 26px;
219 | line-height: 36px;
220 |
221 | letter-spacing: -1px;
222 | }
223 |
224 | b {
225 | font-weight: 600;
226 | }
227 |
228 | a {
229 | color: rgb(0, 102, 204);
230 | text-decoration: none;
231 | }
232 | a:visited {
233 | color: rgba(0, 102, 204, .75);
234 | }
235 | a:hover {
236 | color: black;
237 | }
238 |
239 | p {
240 | margin: 0;
241 | padding: 0;
242 |
243 | margin-top: 20px;
244 | }
245 | p:first-child {
246 | margin-top: 0;
247 | }
248 |
249 | h1 {
250 | font-size: 60px;
251 | line-height: 60px;
252 |
253 | padding: 0;
254 | margin: 0;
255 | margin-top: 200px;
256 | margin-bottom: 5px;
257 | padding-right: 40px;
258 |
259 | font-weight: 600;
260 |
261 | letter-spacing: -3px;
262 |
263 | color: rgb(51, 51, 51);
264 | }
265 |
266 | h2 {
267 | font-size: 45px;
268 | line-height: 45px;
269 |
270 | position: absolute;
271 | bottom: 150px;
272 |
273 | padding: 0;
274 | margin: 0;
275 | padding-right: 40px;
276 |
277 | font-weight: 600;
278 |
279 | letter-spacing: -2px;
280 |
281 | color: rgb(51, 51, 51);
282 | }
283 |
284 | h3 {
285 | font-size: 30px;
286 | line-height: 36px;
287 |
288 | padding: 0;
289 | margin: 0;
290 | padding-right: 40px;
291 |
292 | font-weight: 600;
293 |
294 | letter-spacing: -1px;
295 |
296 | color: rgb(51, 51, 51);
297 | }
298 |
299 | ul {
300 | margin: 0;
301 | padding: 0;
302 | margin-top: 20px;
303 | margin-left: 1.5em;
304 | }
305 | li {
306 | padding: 0;
307 | margin: 0 0 .5em 0;
308 | }
309 |
310 | div.code {
311 | padding: 5px 10px;
312 | margin-top: 20px;
313 | margin-bottom: 20px;
314 | overflow: hidden;
315 |
316 | background: rgb(240, 240, 240);
317 | border: 1px solid rgb(224, 224, 224);
318 | }
319 | pre {
320 | margin: 0;
321 | padding: 0;
322 |
323 | font-family: 'Droid Sans Mono', 'Courier New', monospace;
324 | font-size: 18px;
325 | line-height: 24px;
326 | letter-spacing: -1px;
327 |
328 | color: black;
329 | }
330 |
331 | code {
332 | font-size: 95%;
333 | font-family: 'Droid Sans Mono', 'Courier New', monospace;
334 |
335 | color: black;
336 | }
337 |
338 | article > .image {
339 | text-align: center;
340 | margin-top: 40px;
341 | }
342 |
343 | table {
344 | width: 100%;
345 | border-collapse: collapse;
346 | margin-top: 40px;
347 | }
348 | th {
349 | font-weight: 600;
350 | text-align: left;
351 | }
352 | td,
353 | th {
354 | border: 1px solid rgb(224, 224, 224);
355 | padding: 5px 10px;
356 | vertical-align: top;
357 | }
358 |
359 | p.link {
360 | margin-left: 20px;
361 | }
362 |
363 | /* Code */
364 | div.code {
365 | outline: 0px solid transparent;
366 | }
367 | div.playground {
368 | position: relative;
369 | }
370 | div.output {
371 | position: absolute;
372 | left: 50%;
373 | top: 50%;
374 | right: 40px;
375 | bottom: 40px;
376 | background: #202020;
377 | padding: 5px 10px;
378 | z-index: 2;
379 |
380 | border-radius: 10px;
381 | -o-border-radius: 10px;
382 | -moz-border-radius: 10px;
383 | -webkit-border-radius: 10px;
384 |
385 | }
386 | div.output pre {
387 | margin: 0;
388 | padding: 0;
389 | background: none;
390 | border: none;
391 | width: 100%;
392 | height: 100%;
393 | overflow: auto;
394 | }
395 | div.output .stdout, div.output pre {
396 | color: #e6e6e6;
397 | }
398 | div.output .stderr, div.output .error {
399 | color: rgb(244, 74, 63);
400 | }
401 | div.output .system, div.output .exit {
402 | color: rgb(255, 209, 77)
403 | }
404 | .buttons {
405 | position: relative;
406 | float: right;
407 | top: -60px;
408 | right: 10px;
409 | }
410 | div.output .buttons {
411 | position: absolute;
412 | float: none;
413 | top: auto;
414 | right: 5px;
415 | bottom: 5px;
416 | }
417 |
418 | /* Presenter details */
419 | .presenter {
420 | margin-top: 20px;
421 | }
422 | .presenter p,
423 | .presenter .link {
424 | margin: 0;
425 | font-size: 28px;
426 | line-height: 1.2em;
427 | }
428 |
429 | /* Output resize details */
430 | .ui-resizable-handle {
431 | position: absolute;
432 | }
433 | .ui-resizable-n {
434 | cursor: n-resize;
435 | height: 7px;
436 | width: 100%;
437 | top: -5px;
438 | left: 0;
439 | }
440 | .ui-resizable-w {
441 | cursor: w-resize;
442 | width: 7px;
443 | left: -5px;
444 | top: 0;
445 | height: 100%;
446 | }
447 | .ui-resizable-nw {
448 | cursor: nw-resize;
449 | width: 9px;
450 | height: 9px;
451 | left: -5px;
452 | top: -5px;
453 | }
454 |
--------------------------------------------------------------------------------
/docview/dirtrees.go:
--------------------------------------------------------------------------------
1 | // Copyright 2010 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // This file contains the code dealing with package directory trees.
6 |
7 | package docview
8 |
9 | import (
10 | "bytes"
11 | "go/doc"
12 | "go/parser"
13 | "go/token"
14 | "log"
15 | "os"
16 | "path/filepath"
17 | "strings"
18 | "unicode"
19 | )
20 |
21 | type Directory struct {
22 | Depth int
23 | Path string // includes Name
24 | Name string
25 | Text string // package documentation, if any
26 | Dirs []*Directory // subdirectories
27 | }
28 |
29 | //func isGoFile(fi os.FileInfo) bool {
30 | // name := fi.Name()
31 | // return !fi.IsDir() &&
32 | // len(name) > 0 && name[0] != '.' && // ignore .files
33 | // filepath.Ext(name) == ".go"
34 | //}
35 |
36 | func isGoFile(f os.FileInfo) bool {
37 | // ignore non-Go files
38 | name := f.Name()
39 | return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
40 | }
41 |
42 | func isPkgFile(fi os.FileInfo) bool {
43 | return isGoFile(fi) &&
44 | !strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
45 | }
46 |
47 | func isPkgDir(fi os.FileInfo) bool {
48 | name := fi.Name()
49 | return fi.IsDir() && len(name) > 0 &&
50 | name[0] != '_' && name[0] != '.' // ignore _files and .files
51 | }
52 |
53 | func firstSentence(s string) string {
54 | i := -1 // index+1 of first terminator (punctuation ending a sentence)
55 | j := -1 // index+1 of first terminator followed by white space
56 | prev := 'A'
57 | for k, ch := range s {
58 | k1 := k + 1
59 | if ch == '.' || ch == '!' || ch == '?' {
60 | if i < 0 {
61 | i = k1 // first terminator
62 | }
63 | if k1 < len(s) && s[k1] <= ' ' {
64 | if j < 0 {
65 | j = k1 // first terminator followed by white space
66 | }
67 | if !unicode.IsUpper(prev) {
68 | j = k1
69 | break
70 | }
71 | }
72 | }
73 | prev = ch
74 | }
75 |
76 | if j < 0 {
77 | // use the next best terminator
78 | j = i
79 | if j < 0 {
80 | // no terminator at all, use the entire string
81 | j = len(s)
82 | }
83 | }
84 |
85 | return s[0:j]
86 | }
87 |
88 | type treeBuilder struct {
89 | pathFilter func(string) bool
90 | maxDepth int
91 | }
92 |
93 | func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
94 | if b.pathFilter != nil && !b.pathFilter(path) {
95 | return nil
96 | }
97 |
98 | if depth >= b.maxDepth {
99 | // return a dummy directory so that the parent directory
100 | // doesn't get discarded just because we reached the max
101 | // directory depth
102 | return &Directory{depth, path, name, "", nil}
103 | }
104 |
105 | list, err := fs.ReadDir(path)
106 | if err != nil {
107 | // newDirTree is called with a path that should be a package
108 | // directory; errors here should not happen, but if they do,
109 | // we want to know about them
110 | log.Printf("ReadDir(%s): %s", path, err)
111 | }
112 |
113 | // determine number of subdirectories and if there are package files
114 | ndirs := 0
115 | hasPkgFiles := false
116 | var synopses [4]string // prioritized package documentation (0 == highest priority)
117 | for _, d := range list {
118 | switch {
119 | case isPkgDir(d):
120 | ndirs++
121 | case isPkgFile(d):
122 | // looks like a package file, but may just be a file ending in ".go";
123 | // don't just count it yet (otherwise we may end up with hasPkgFiles even
124 | // though the directory doesn't contain any real package files - was bug)
125 | if synopses[0] == "" {
126 | // no "optimal" package synopsis yet; continue to collect synopses
127 | //file, err := parseFile(fset, filepath.Join(path, d.Name()),
128 | //parser.ParseComments|parser.PackageClauseOnly)
129 | file, err := parser.ParseFile(fset, filepath.Join(path, d.Name()), nil,
130 | parser.ParseComments|parser.PackageClauseOnly)
131 |
132 | if err == nil {
133 | hasPkgFiles = true
134 | if file.Doc != nil {
135 | // prioritize documentation
136 | i := -1
137 | switch file.Name.Name {
138 | case name:
139 | i = 0 // normal case: directory name matches package name
140 | case fakePkgName:
141 | i = 1 // synopses for commands
142 | case "main":
143 | i = 2 // directory contains a main package
144 | default:
145 | i = 3 // none of the above
146 | }
147 | if 0 <= i && i < len(synopses) && synopses[i] == "" {
148 | synopses[i] = doc.Synopsis(file.Doc.Text())
149 | }
150 | }
151 | }
152 | }
153 | }
154 | }
155 |
156 | // create subdirectory tree
157 | var dirs []*Directory
158 | if ndirs > 0 {
159 | dirs = make([]*Directory, ndirs)
160 | i := 0
161 | for _, d := range list {
162 | if isPkgDir(d) {
163 | name := d.Name()
164 | dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
165 | if dd != nil {
166 | dirs[i] = dd
167 | i++
168 | }
169 | }
170 | }
171 | dirs = dirs[0:i]
172 | }
173 |
174 | // if there are no package files and no subdirectories
175 | // containing package files, ignore the directory
176 | if !hasPkgFiles && len(dirs) == 0 {
177 | return nil
178 | }
179 |
180 | // select the highest-priority synopsis for the directory entry, if any
181 | synopsis := ""
182 | for _, synopsis = range synopses {
183 | if synopsis != "" {
184 | break
185 | }
186 | }
187 |
188 | return &Directory{depth, path, name, synopsis, dirs}
189 | }
190 |
191 | // newDirectory creates a new package directory tree with at most maxDepth
192 | // levels, anchored at root. The result tree is pruned such that it only
193 | // contains directories that contain package files or that contain
194 | // subdirectories containing package files (transitively). If a non-nil
195 | // pathFilter is provided, directory paths additionally must be accepted
196 | // by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
197 | // provided for maxDepth, nodes at larger depths are pruned as well; they
198 | // are assumed to contain package files even if their contents are not known
199 | // (i.e., in this case the tree may contain directories w/o any package files).
200 | //
201 | func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
202 | // The root could be a symbolic link so use Stat not Lstat.
203 | d, err := fs.Stat(root)
204 | // If we fail here, report detailed error messages; otherwise
205 | // is is hard to see why a directory tree was not built.
206 | switch {
207 | case err != nil:
208 | log.Printf("newDirectory(%s): %s", root, err)
209 | return nil
210 | case !isPkgDir(d):
211 | log.Printf("newDirectory(%s): not a package directory", root)
212 | return nil
213 | }
214 | if maxDepth < 0 {
215 | maxDepth = 1e6 // "infinity"
216 | }
217 | b := treeBuilder{pathFilter, maxDepth}
218 | // the file set provided is only for local parsing, no position
219 | // information escapes and thus we don't need to save the set
220 | return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
221 | }
222 |
223 | func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
224 | if dir != nil {
225 | if len(dir.Dirs) == 0 {
226 | buf.WriteString(dir.Path)
227 | buf.WriteByte('\n')
228 | return
229 | }
230 |
231 | for _, d := range dir.Dirs {
232 | d.writeLeafs(buf)
233 | }
234 | }
235 | }
236 |
237 | func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
238 | if dir != nil {
239 | if !skipRoot {
240 | c <- dir
241 | }
242 | for _, d := range dir.Dirs {
243 | d.walk(c, false)
244 | }
245 | }
246 | }
247 |
248 | func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
249 | c := make(chan *Directory)
250 | go func() {
251 | dir.walk(c, skipRoot)
252 | close(c)
253 | }()
254 | return c
255 | }
256 |
257 | func (dir *Directory) lookupLocal(name string) *Directory {
258 | for _, d := range dir.Dirs {
259 | if d.Name == name {
260 | return d
261 | }
262 | }
263 | return nil
264 | }
265 |
266 | // lookup looks for the *Directory for a given path, relative to dir.
267 | func (dir *Directory) lookup(path string) *Directory {
268 | d := strings.Split(dir.Path, string(filepath.Separator))
269 | p := strings.Split(path, string(filepath.Separator))
270 | i := 0
271 | for i < len(d) {
272 | if i >= len(p) || d[i] != p[i] {
273 | return nil
274 | }
275 | i++
276 | }
277 | for dir != nil && i < len(p) {
278 | dir = dir.lookupLocal(p[i])
279 | i++
280 | }
281 | return dir
282 | }
283 |
284 | // DirEntry describes a directory entry. The Depth and Height values
285 | // are useful for presenting an entry in an indented fashion.
286 | //
287 | type DirEntry struct {
288 | Depth int // >= 0
289 | Height int // = DirList.MaxHeight - Depth, > 0
290 | Path string // includes Name, relative to DirList root
291 | Name string
292 | Synopsis string
293 | }
294 |
295 | type DirList struct {
296 | MaxHeight int // directory tree height, > 0
297 | List []DirEntry
298 | }
299 |
300 | // listing creates a (linear) directory listing from a directory tree.
301 | // If skipRoot is set, the root directory itself is excluded from the list.
302 | //
303 | func (root *Directory) listing(skipRoot bool) *DirList {
304 | if root == nil {
305 | return nil
306 | }
307 |
308 | // determine number of entries n and maximum height
309 | n := 0
310 | minDepth := 1 << 30 // infinity
311 | maxDepth := 0
312 | for d := range root.iter(skipRoot) {
313 | n++
314 | if minDepth > d.Depth {
315 | minDepth = d.Depth
316 | }
317 | if maxDepth < d.Depth {
318 | maxDepth = d.Depth
319 | }
320 | }
321 | maxHeight := maxDepth - minDepth + 1
322 |
323 | if n == 0 {
324 | return nil
325 | }
326 |
327 | // create list
328 | list := make([]DirEntry, n)
329 | i := 0
330 | for d := range root.iter(skipRoot) {
331 | p := &list[i]
332 | p.Depth = d.Depth - minDepth
333 | p.Height = maxHeight - p.Depth
334 | // the path is relative to root.Path - remove the root.Path
335 | // prefix (the prefix should always be present but avoid
336 | // crashes and check)
337 | path := d.Path
338 | if strings.HasPrefix(d.Path, root.Path) {
339 | path = d.Path[len(root.Path):]
340 | }
341 | // remove trailing separator if any - path must be relative
342 | if len(path) > 0 && path[0] == filepath.Separator {
343 | path = path[1:]
344 | }
345 | p.Path = filepath.ToSlash(path)
346 | p.Name = d.Name
347 | p.Synopsis = d.Text
348 | i++
349 | }
350 |
351 | return &DirList{maxHeight, list}
352 | }
353 |
--------------------------------------------------------------------------------
/pkgs/pkgs.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package pkgs
6 |
7 | import (
8 | "encoding/json"
9 | "fmt"
10 | "go/build"
11 | "os"
12 | "path/filepath"
13 | "runtime"
14 | "sort"
15 | "strings"
16 | "sync"
17 |
18 | "github.com/visualfc/gotools/pkg/command"
19 | )
20 |
21 | var Command = &command.Command{
22 | Run: runPkgs,
23 | UsageLine: "pkgs [-list|-json] [-std]",
24 | Short: "print go package",
25 | Long: `print go package.`,
26 | }
27 |
28 | var (
29 | pkgsList bool
30 | pkgsJson bool
31 | pkgsSimple bool
32 | pkgsFind string
33 | pkgsStd bool
34 | pkgsPkgOnly bool
35 | pkgsSkipGoroot bool
36 | )
37 |
38 | func init() {
39 | Command.Flag.BoolVar(&pkgsList, "list", false, "list all package")
40 | Command.Flag.BoolVar(&pkgsJson, "json", false, "json format")
41 | Command.Flag.BoolVar(&pkgsSimple, "simple", false, "simple format")
42 | Command.Flag.BoolVar(&pkgsStd, "std", false, "std library")
43 | Command.Flag.BoolVar(&pkgsPkgOnly, "pkg", false, "pkg only")
44 | Command.Flag.BoolVar(&pkgsSkipGoroot, "skip_goroot", false, "skip goroot")
45 | Command.Flag.StringVar(&pkgsFind, "find", "", "find package by name")
46 | }
47 |
48 | func runPkgs(cmd *command.Command, args []string) error {
49 | runtime.GOMAXPROCS(runtime.NumCPU())
50 | if len(args) != 0 {
51 | cmd.Usage()
52 | return os.ErrInvalid
53 | }
54 | //pkgIndexOnce.Do(loadPkgsList)
55 | var flag LoadFlag
56 | if pkgsStd {
57 | flag = LoadGoroot
58 | } else if pkgsSkipGoroot {
59 | flag = LoadSkipGoroot
60 | } else {
61 | flag = LoadAll
62 | }
63 | var pp PathPkgsIndex
64 | pp.LoadIndex(build.Default, flag)
65 | pp.Sort()
66 | export := func(pkg *build.Package) {
67 | if pkgsJson {
68 | var p GoPackage
69 | p.copyBuild(pkg)
70 | b, err := json.MarshalIndent(&p, "", "\t")
71 | if err == nil {
72 | cmd.Stdout.Write(b)
73 | cmd.Stdout.Write([]byte{'\n'})
74 | }
75 | } else if pkgsSimple {
76 | cmd.Println(pkg.Name + "::" + pkg.ImportPath + "::" + pkg.Dir)
77 | } else {
78 | cmd.Println(pkg.ImportPath)
79 | }
80 | }
81 | if pkgsList {
82 | for _, pi := range pp.Indexs {
83 | for _, pkg := range pi.Pkgs {
84 | if pkgsPkgOnly && pkg.IsCommand() {
85 | continue
86 | }
87 | export(pkg)
88 | }
89 | }
90 | } else if pkgsFind != "" {
91 | for _, pi := range pp.Indexs {
92 | for _, pkg := range pi.Pkgs {
93 | if pkgsPkgOnly && pkg.IsCommand() {
94 | continue
95 | }
96 | if pkg.Name == pkgsFind {
97 | export(pkg)
98 | break
99 | }
100 | }
101 | }
102 | }
103 | return nil
104 | }
105 |
106 | // A Package describes a single package found in a directory.
107 | type GoPackage struct {
108 | // Note: These fields are part of the go command's public API.
109 | // See list.go. It is okay to add fields, but not to change or
110 | // remove existing ones. Keep in sync with list.go
111 | Dir string `json:",omitempty"` // directory containing package sources
112 | ImportPath string `json:",omitempty"` // import path of package in dir
113 | Name string `json:",omitempty"` // package name
114 | Doc string `json:",omitempty"` // package documentation string
115 | Target string `json:",omitempty"` // install path
116 | Goroot bool `json:",omitempty"` // is this package found in the Go root?
117 | Standard bool `json:",omitempty"` // is this package part of the standard Go library?
118 | Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
119 | Root string `json:",omitempty"` // Go root or Go path dir containing this package
120 | ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
121 |
122 | // Source files
123 | GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
124 | CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
125 | IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
126 | CFiles []string `json:",omitempty"` // .c source files
127 | CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
128 | MFiles []string `json:",omitempty"` // .m source files
129 | HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
130 | SFiles []string `json:",omitempty"` // .s source files
131 | SwigFiles []string `json:",omitempty"` // .swig files
132 | SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
133 | SysoFiles []string `json:",omitempty"` // .syso system object files added to package
134 |
135 | // Cgo directives
136 | CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
137 | CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor
138 | CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler
139 | CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
140 | CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
141 |
142 | // Dependency information
143 | Imports []string `json:",omitempty"` // import paths used by this package
144 | Deps []string `json:",omitempty"` // all (recursively) imported dependencies
145 |
146 | // Error information
147 | Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
148 |
149 | // Test information
150 | TestGoFiles []string `json:",omitempty"` // _test.go files in package
151 | TestImports []string `json:",omitempty"` // imports from TestGoFiles
152 | XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
153 | XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
154 |
155 | // Unexported fields are not part of the public API.
156 | build *build.Package
157 | pkgdir string // overrides build.PkgDir
158 | // imports []*goapi.Package
159 | // deps []*goapi.Package
160 | gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
161 | sfiles []string
162 | allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
163 | target string // installed file for this package (may be executable)
164 | fake bool // synthesized package
165 | forceBuild bool // this package must be rebuilt
166 | forceLibrary bool // this package is a library (even if named "main")
167 | cmdline bool // defined by files listed on command line
168 | local bool // imported via local path (./ or ../)
169 | localPrefix string // interpret ./ and ../ imports relative to this prefix
170 | exeName string // desired name for temporary executable
171 | coverMode string // preprocess Go source files with the coverage tool in this mode
172 | coverVars map[string]*CoverVar // variables created by coverage analysis
173 | omitDWARF bool // tell linker not to write DWARF information
174 | }
175 |
176 | // CoverVar holds the name of the generated coverage variables targeting the named file.
177 | type CoverVar struct {
178 | File string // local file name
179 | Var string // name of count struct
180 | }
181 |
182 | func (p *GoPackage) copyBuild(pp *build.Package) {
183 | p.build = pp
184 |
185 | p.Dir = pp.Dir
186 | p.ImportPath = pp.ImportPath
187 | p.Name = pp.Name
188 | p.Doc = pp.Doc
189 | p.Root = pp.Root
190 | p.ConflictDir = pp.ConflictDir
191 | // TODO? Target
192 | p.Goroot = pp.Goroot
193 | p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
194 | p.GoFiles = pp.GoFiles
195 | p.CgoFiles = pp.CgoFiles
196 | p.IgnoredGoFiles = pp.IgnoredGoFiles
197 | p.CFiles = pp.CFiles
198 | p.CXXFiles = pp.CXXFiles
199 | p.MFiles = pp.MFiles
200 | p.HFiles = pp.HFiles
201 | p.SFiles = pp.SFiles
202 | p.SwigFiles = pp.SwigFiles
203 | p.SwigCXXFiles = pp.SwigCXXFiles
204 | p.SysoFiles = pp.SysoFiles
205 | p.CgoCFLAGS = pp.CgoCFLAGS
206 | p.CgoCPPFLAGS = pp.CgoCPPFLAGS
207 | p.CgoCXXFLAGS = pp.CgoCXXFLAGS
208 | p.CgoLDFLAGS = pp.CgoLDFLAGS
209 | p.CgoPkgConfig = pp.CgoPkgConfig
210 | p.Imports = pp.Imports
211 | p.TestGoFiles = pp.TestGoFiles
212 | p.TestImports = pp.TestImports
213 | p.XTestGoFiles = pp.XTestGoFiles
214 | p.XTestImports = pp.XTestImports
215 | }
216 |
217 | type PathPkgsIndex struct {
218 | Indexs []*PkgsIndex
219 | }
220 |
221 | type LoadFlag int
222 |
223 | const (
224 | LoadGoroot LoadFlag = iota
225 | LoadSkipGoroot
226 | LoadAll
227 | )
228 |
229 | func (p *PathPkgsIndex) LoadIndex(context build.Context, flag LoadFlag) {
230 | var wg sync.WaitGroup
231 | if flag == LoadGoroot {
232 | context.GOPATH = ""
233 | }
234 | var srcDirs []string
235 | goroot := context.GOROOT
236 | gopath := context.GOPATH
237 | context.GOPATH = ""
238 |
239 | if flag != LoadSkipGoroot {
240 | //go1.4 go/src/
241 | //go1.3 go/src/pkg; go/src/cmd
242 | _, err := os.Stat(filepath.Join(goroot, "src/pkg/runtime"))
243 | if err == nil {
244 | for _, v := range context.SrcDirs() {
245 | if strings.HasSuffix(v, "pkg") {
246 | srcDirs = append(srcDirs, v[:len(v)-3]+"cmd")
247 | }
248 | srcDirs = append(srcDirs, v)
249 | }
250 | } else {
251 | srcDirs = append(srcDirs, filepath.Join(goroot, "src"))
252 | }
253 | }
254 | iRoot := len(srcDirs)
255 | context.GOPATH = gopath
256 | context.GOROOT = ""
257 | for _, v := range context.SrcDirs() {
258 | srcDirs = append(srcDirs, v)
259 | }
260 | context.GOROOT = goroot
261 | for i, path := range srcDirs {
262 | pi := &PkgsIndex{}
263 | pi.Root = path
264 | pi.Goroot = (i < iRoot)
265 | p.Indexs = append(p.Indexs, pi)
266 | pkgsGate.enter()
267 | f, err := os.Open(path)
268 | if err != nil {
269 | pkgsGate.leave()
270 | continue
271 | }
272 | children, err := f.Readdir(-1)
273 | f.Close()
274 | pkgsGate.leave()
275 | if err != nil {
276 | fmt.Fprint(os.Stderr, err)
277 | continue
278 | }
279 | for _, child := range children {
280 | if child.IsDir() {
281 | wg.Add(1)
282 | go func(path, name string) {
283 | defer wg.Done()
284 | pi.loadPkgsPath(&wg, path, name)
285 | }(path, child.Name())
286 | }
287 | }
288 | }
289 | wg.Wait()
290 | }
291 |
292 | func (p *PathPkgsIndex) Sort() {
293 | for _, v := range p.Indexs {
294 | v.sort()
295 | }
296 | }
297 |
298 | type PkgsIndex struct {
299 | sync.Mutex
300 | Pkgs []*build.Package
301 | Root string
302 | Goroot bool
303 | }
304 |
305 | func (p *PkgsIndex) sort() {
306 | sort.Sort(PkgSlice(p.Pkgs))
307 | }
308 |
309 | type PkgSlice []*build.Package
310 |
311 | func (p PkgSlice) Len() int {
312 | return len([]*build.Package(p))
313 | }
314 |
315 | func (p PkgSlice) Less(i, j int) bool {
316 | if p[i].IsCommand() && !p[j].IsCommand() {
317 | return true
318 | } else if !p[i].IsCommand() && p[j].IsCommand() {
319 | return false
320 | }
321 | return p[i].ImportPath < p[j].ImportPath
322 | }
323 |
324 | func (p PkgSlice) Swap(i, j int) {
325 | p[i], p[j] = p[j], p[i]
326 | }
327 |
328 | // pkgsgate protects the OS & filesystem from too much concurrency.
329 | // Too much disk I/O -> too many threads -> swapping and bad scheduling.
330 | // gate is a semaphore for limiting concurrency.
331 | type gate chan struct{}
332 |
333 | func (g gate) enter() { g <- struct{}{} }
334 | func (g gate) leave() { <-g }
335 |
336 | var pkgsGate = make(gate, 8)
337 |
338 | func (p *PkgsIndex) loadPkgsPath(wg *sync.WaitGroup, root, pkgrelpath string) {
339 | importpath := filepath.ToSlash(pkgrelpath)
340 | dir := filepath.Join(root, importpath)
341 |
342 | pkgsGate.enter()
343 | defer pkgsGate.leave()
344 | pkgDir, err := os.Open(dir)
345 | if err != nil {
346 | return
347 | }
348 | children, err := pkgDir.Readdir(-1)
349 | pkgDir.Close()
350 | if err != nil {
351 | return
352 | }
353 | // hasGo tracks whether a directory actually appears to be a
354 | // Go source code directory. If $GOPATH == $HOME, and
355 | // $HOME/src has lots of other large non-Go projects in it,
356 | // then the calls to importPathToName below can be expensive.
357 | hasGo := false
358 | for _, child := range children {
359 | name := child.Name()
360 | if name == "" {
361 | continue
362 | }
363 | if c := name[0]; c == '.' || ('0' <= c && c <= '9') {
364 | continue
365 | }
366 | if strings.HasSuffix(name, ".go") {
367 | hasGo = true
368 | }
369 | if child.IsDir() {
370 | if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") || name == "testdata" {
371 | continue
372 | }
373 | wg.Add(1)
374 | go func(root, name string) {
375 | defer wg.Done()
376 | p.loadPkgsPath(wg, root, name)
377 | }(root, filepath.Join(importpath, name))
378 | }
379 | }
380 | if hasGo {
381 | buildPkg, err := build.ImportDir(dir, 0)
382 | if err == nil {
383 | if buildPkg.ImportPath == "." {
384 | buildPkg.ImportPath = filepath.ToSlash(pkgrelpath)
385 | buildPkg.Root = root
386 | buildPkg.Goroot = p.Goroot
387 | }
388 | p.Lock()
389 | p.Pkgs = append(p.Pkgs, buildPkg)
390 | p.Unlock()
391 | }
392 | }
393 | }
394 |
--------------------------------------------------------------------------------
/gopresent/static/slides.js:
--------------------------------------------------------------------------------
1 | // Copyright 2012 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | var PERMANENT_URL_PREFIX = 'static/';
6 |
7 | var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next'];
8 |
9 | var PM_TOUCH_SENSITIVITY = 15;
10 |
11 | var curSlide;
12 |
13 | /* ---------------------------------------------------------------------- */
14 | /* classList polyfill by Eli Grey
15 | * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */
16 |
17 | if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
18 |
19 | (function (view) {
20 |
21 | var
22 | classListProp = "classList"
23 | , protoProp = "prototype"
24 | , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
25 | , objCtr = Object
26 | strTrim = String[protoProp].trim || function () {
27 | return this.replace(/^\s+|\s+$/g, "");
28 | }
29 | , arrIndexOf = Array[protoProp].indexOf || function (item) {
30 | for (var i = 0, len = this.length; i < len; i++) {
31 | if (i in this && this[i] === item) {
32 | return i;
33 | }
34 | }
35 | return -1;
36 | }
37 | // Vendors: please allow content code to instantiate DOMExceptions
38 | , DOMEx = function (type, message) {
39 | this.name = type;
40 | this.code = DOMException[type];
41 | this.message = message;
42 | }
43 | , checkTokenAndGetIndex = function (classList, token) {
44 | if (token === "") {
45 | throw new DOMEx(
46 | "SYNTAX_ERR"
47 | , "An invalid or illegal string was specified"
48 | );
49 | }
50 | if (/\s/.test(token)) {
51 | throw new DOMEx(
52 | "INVALID_CHARACTER_ERR"
53 | , "String contains an invalid character"
54 | );
55 | }
56 | return arrIndexOf.call(classList, token);
57 | }
58 | , ClassList = function (elem) {
59 | var
60 | trimmedClasses = strTrim.call(elem.className)
61 | , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
62 | ;
63 | for (var i = 0, len = classes.length; i < len; i++) {
64 | this.push(classes[i]);
65 | }
66 | this._updateClassName = function () {
67 | elem.className = this.toString();
68 | };
69 | }
70 | , classListProto = ClassList[protoProp] = []
71 | , classListGetter = function () {
72 | return new ClassList(this);
73 | }
74 | ;
75 | // Most DOMException implementations don't allow calling DOMException's toString()
76 | // on non-DOMExceptions. Error's toString() is sufficient here.
77 | DOMEx[protoProp] = Error[protoProp];
78 | classListProto.item = function (i) {
79 | return this[i] || null;
80 | };
81 | classListProto.contains = function (token) {
82 | token += "";
83 | return checkTokenAndGetIndex(this, token) !== -1;
84 | };
85 | classListProto.add = function (token) {
86 | token += "";
87 | if (checkTokenAndGetIndex(this, token) === -1) {
88 | this.push(token);
89 | this._updateClassName();
90 | }
91 | };
92 | classListProto.remove = function (token) {
93 | token += "";
94 | var index = checkTokenAndGetIndex(this, token);
95 | if (index !== -1) {
96 | this.splice(index, 1);
97 | this._updateClassName();
98 | }
99 | };
100 | classListProto.toggle = function (token) {
101 | token += "";
102 | if (checkTokenAndGetIndex(this, token) === -1) {
103 | this.add(token);
104 | } else {
105 | this.remove(token);
106 | }
107 | };
108 | classListProto.toString = function () {
109 | return this.join(" ");
110 | };
111 |
112 | if (objCtr.defineProperty) {
113 | var classListPropDesc = {
114 | get: classListGetter
115 | , enumerable: true
116 | , configurable: true
117 | };
118 | try {
119 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
120 | } catch (ex) { // IE 8 doesn't support enumerable:true
121 | if (ex.number === -0x7FF5EC54) {
122 | classListPropDesc.enumerable = false;
123 | objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
124 | }
125 | }
126 | } else if (objCtr[protoProp].__defineGetter__) {
127 | elemCtrProto.__defineGetter__(classListProp, classListGetter);
128 | }
129 |
130 | }(self));
131 |
132 | }
133 | /* ---------------------------------------------------------------------- */
134 |
135 | /* Slide movement */
136 |
137 | function getSlideEl(no) {
138 | if ((no < 0) || (no >= slideEls.length)) {
139 | return null;
140 | } else {
141 | return slideEls[no];
142 | }
143 | };
144 |
145 | function updateSlideClass(slideNo, className) {
146 | var el = getSlideEl(slideNo);
147 |
148 | if (!el) {
149 | return;
150 | }
151 |
152 | if (className) {
153 | el.classList.add(className);
154 | }
155 |
156 | for (var i in SLIDE_CLASSES) {
157 | if (className != SLIDE_CLASSES[i]) {
158 | el.classList.remove(SLIDE_CLASSES[i]);
159 | }
160 | }
161 | };
162 |
163 | function updateSlides() {
164 | for (var i = 0; i < slideEls.length; i++) {
165 | switch (i) {
166 | case curSlide - 2:
167 | updateSlideClass(i, 'far-past');
168 | break;
169 | case curSlide - 1:
170 | updateSlideClass(i, 'past');
171 | break;
172 | case curSlide:
173 | updateSlideClass(i, 'current');
174 | break;
175 | case curSlide + 1:
176 | updateSlideClass(i, 'next');
177 | break;
178 | case curSlide + 2:
179 | updateSlideClass(i, 'far-next');
180 | break;
181 | default:
182 | updateSlideClass(i);
183 | break;
184 | }
185 | }
186 |
187 | triggerLeaveEvent(curSlide - 1);
188 | triggerEnterEvent(curSlide);
189 |
190 | window.setTimeout(function() {
191 | // Hide after the slide
192 | disableSlideFrames(curSlide - 2);
193 | }, 301);
194 |
195 | enableSlideFrames(curSlide - 1);
196 | enableSlideFrames(curSlide + 2);
197 |
198 | updateHash();
199 | };
200 |
201 | function prevSlide() {
202 | if (curSlide > 0) {
203 | curSlide--;
204 |
205 | updateSlides();
206 | }
207 | };
208 |
209 | function nextSlide() {
210 | if (curSlide < slideEls.length - 1) {
211 | curSlide++;
212 |
213 | updateSlides();
214 | }
215 | };
216 |
217 | /* Slide events */
218 |
219 | function triggerEnterEvent(no) {
220 | var el = getSlideEl(no);
221 | if (!el) {
222 | return;
223 | }
224 |
225 | var onEnter = el.getAttribute('onslideenter');
226 | if (onEnter) {
227 | new Function(onEnter).call(el);
228 | }
229 |
230 | var evt = document.createEvent('Event');
231 | evt.initEvent('slideenter', true, true);
232 | evt.slideNumber = no + 1; // Make it readable
233 |
234 | el.dispatchEvent(evt);
235 | };
236 |
237 | function triggerLeaveEvent(no) {
238 | var el = getSlideEl(no);
239 | if (!el) {
240 | return;
241 | }
242 |
243 | var onLeave = el.getAttribute('onslideleave');
244 | if (onLeave) {
245 | new Function(onLeave).call(el);
246 | }
247 |
248 | var evt = document.createEvent('Event');
249 | evt.initEvent('slideleave', true, true);
250 | evt.slideNumber = no + 1; // Make it readable
251 |
252 | el.dispatchEvent(evt);
253 | };
254 |
255 | /* Touch events */
256 |
257 | function handleTouchStart(event) {
258 | if (event.touches.length == 1) {
259 | touchDX = 0;
260 | touchDY = 0;
261 |
262 | touchStartX = event.touches[0].pageX;
263 | touchStartY = event.touches[0].pageY;
264 |
265 | document.body.addEventListener('touchmove', handleTouchMove, true);
266 | document.body.addEventListener('touchend', handleTouchEnd, true);
267 | }
268 | };
269 |
270 | function handleTouchMove(event) {
271 | if (event.touches.length > 1) {
272 | cancelTouch();
273 | } else {
274 | touchDX = event.touches[0].pageX - touchStartX;
275 | touchDY = event.touches[0].pageY - touchStartY;
276 | event.preventDefault();
277 | }
278 | };
279 |
280 | function handleTouchEnd(event) {
281 | var dx = Math.abs(touchDX);
282 | var dy = Math.abs(touchDY);
283 |
284 | if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) {
285 | if (touchDX > 0) {
286 | prevSlide();
287 | } else {
288 | nextSlide();
289 | }
290 | }
291 |
292 | cancelTouch();
293 | };
294 |
295 | function cancelTouch() {
296 | document.body.removeEventListener('touchmove', handleTouchMove, true);
297 | document.body.removeEventListener('touchend', handleTouchEnd, true);
298 | };
299 |
300 | /* Preloading frames */
301 |
302 | function disableSlideFrames(no) {
303 | var el = getSlideEl(no);
304 | if (!el) {
305 | return;
306 | }
307 |
308 | var frames = el.getElementsByTagName('iframe');
309 | for (var i = 0, frame; frame = frames[i]; i++) {
310 | disableFrame(frame);
311 | }
312 | };
313 |
314 | function enableSlideFrames(no) {
315 | var el = getSlideEl(no);
316 | if (!el) {
317 | return;
318 | }
319 |
320 | var frames = el.getElementsByTagName('iframe');
321 | for (var i = 0, frame; frame = frames[i]; i++) {
322 | enableFrame(frame);
323 | }
324 | };
325 |
326 | function disableFrame(frame) {
327 | frame.src = 'about:blank';
328 | };
329 |
330 | function enableFrame(frame) {
331 | var src = frame._src;
332 |
333 | if (frame.src != src && src != 'about:blank') {
334 | frame.src = src;
335 | }
336 | };
337 |
338 | function setupFrames() {
339 | var frames = document.querySelectorAll('iframe');
340 | for (var i = 0, frame; frame = frames[i]; i++) {
341 | frame._src = frame.src;
342 | disableFrame(frame);
343 | }
344 |
345 | enableSlideFrames(curSlide);
346 | enableSlideFrames(curSlide + 1);
347 | enableSlideFrames(curSlide + 2);
348 | };
349 |
350 | function setupInteraction() {
351 | /* Clicking and tapping */
352 |
353 | var el = document.createElement('div');
354 | el.className = 'slide-area';
355 | el.id = 'prev-slide-area';
356 | el.addEventListener('click', prevSlide, false);
357 | document.querySelector('section.slides').appendChild(el);
358 |
359 | var el = document.createElement('div');
360 | el.className = 'slide-area';
361 | el.id = 'next-slide-area';
362 | el.addEventListener('click', nextSlide, false);
363 | document.querySelector('section.slides').appendChild(el);
364 |
365 | /* Swiping */
366 |
367 | document.body.addEventListener('touchstart', handleTouchStart, false);
368 | }
369 |
370 | /* Hash functions */
371 |
372 | function getCurSlideFromHash() {
373 | var slideNo = parseInt(location.hash.substr(1));
374 |
375 | if (slideNo) {
376 | curSlide = slideNo - 1;
377 | } else {
378 | curSlide = 0;
379 | }
380 | };
381 |
382 | function updateHash() {
383 | location.replace('#' + (curSlide + 1));
384 | };
385 |
386 | /* Event listeners */
387 |
388 | function handleBodyKeyDown(event) {
389 | // If we're in a code element, only handle pgup/down.
390 | var inCode = event.target.classList.contains("code");
391 |
392 | switch (event.keyCode) {
393 | case 39: // right arrow
394 | case 13: // Enter
395 | case 32: // space
396 | if (inCode) break;
397 | case 34: // PgDn
398 | nextSlide();
399 | event.preventDefault();
400 | break;
401 |
402 | case 37: // left arrow
403 | case 8: // Backspace
404 | if (inCode) break;
405 | case 33: // PgUp
406 | prevSlide();
407 | event.preventDefault();
408 | break;
409 |
410 | case 40: // down arrow
411 | if (inCode) break;
412 | nextSlide();
413 | event.preventDefault();
414 | break;
415 |
416 | case 38: // up arrow
417 | if (inCode) break;
418 | prevSlide();
419 | event.preventDefault();
420 | break;
421 | }
422 | };
423 |
424 | function addEventListeners() {
425 | document.addEventListener('keydown', handleBodyKeyDown, false);
426 | };
427 |
428 | /* Initialization */
429 |
430 | function addFontStyle() {
431 | var el = document.createElement('link');
432 | el.rel = 'stylesheet';
433 | el.type = 'text/css';
434 | el.href = '//fonts.googleapis.com/css?family=' +
435 | 'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono';
436 |
437 | document.body.appendChild(el);
438 | };
439 |
440 | function addGeneralStyle() {
441 | var el = document.createElement('link');
442 | el.rel = 'stylesheet';
443 | el.type = 'text/css';
444 | el.href = PERMANENT_URL_PREFIX + 'styles.css';
445 | document.body.appendChild(el);
446 |
447 | var el = document.createElement('meta');
448 | el.name = 'viewport';
449 | el.content = 'width=1100,height=750';
450 | document.querySelector('head').appendChild(el);
451 |
452 | var el = document.createElement('meta');
453 | el.name = 'apple-mobile-web-app-capable';
454 | el.content = 'yes';
455 | document.querySelector('head').appendChild(el);
456 | };
457 |
458 | function addPrintStyle() {
459 | var el = document.createElement('link');
460 | el.rel = 'stylesheet';
461 | el.type = 'text/css';
462 | el.media = "print";
463 | el.href = PERMANENT_URL_PREFIX + 'print.css';
464 | document.body.appendChild(el);
465 | };
466 |
467 | function handleDomLoaded() {
468 | slideEls = document.querySelectorAll('section.slides > article');
469 |
470 | setupFrames();
471 |
472 | addFontStyle();
473 | addGeneralStyle();
474 | addPrintStyle();
475 | addEventListeners();
476 |
477 | updateSlides();
478 |
479 | setupInteraction();
480 |
481 | document.body.classList.add('loaded');
482 | };
483 |
484 | function initialize() {
485 | getCurSlideFromHash();
486 |
487 | if (window['_DEBUG']) {
488 | PERMANENT_URL_PREFIX = '../';
489 | }
490 |
491 | if (window['_DCL']) {
492 | handleDomLoaded();
493 | } else {
494 | document.addEventListener('DOMContentLoaded', handleDomLoaded, false);
495 | }
496 | }
497 |
498 | // If ?debug exists then load the script relative instead of absolute
499 | if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) {
500 | document.addEventListener('DOMContentLoaded', function() {
501 | // Avoid missing the DomContentLoaded event
502 | window['_DCL'] = true
503 | }, false);
504 |
505 | window['_DEBUG'] = true;
506 | var script = document.createElement('script');
507 | script.type = 'text/javascript';
508 | script.src = '../slides.js';
509 | var s = document.getElementsByTagName('script')[0];
510 | s.parentNode.insertBefore(script, s);
511 |
512 | // Remove this script
513 | s.parentNode.removeChild(s);
514 | } else {
515 | initialize();
516 | }
517 |
--------------------------------------------------------------------------------
/astview/astview.go:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2015 visualfc . All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | package astview
6 |
7 | import (
8 | "fmt"
9 | "go/ast"
10 | "go/parser"
11 | "go/token"
12 | "go/types"
13 | "io"
14 | "io/ioutil"
15 | "os"
16 | "path/filepath"
17 | "sort"
18 | "strconv"
19 | "strings"
20 |
21 | "github.com/visualfc/gotools/pkg/command"
22 | "github.com/visualfc/gotools/pkg/pkgutil"
23 | )
24 |
25 | var Command = &command.Command{
26 | Run: runAstView,
27 | UsageLine: "astview [-stdin] files...",
28 | Short: "print go files astview",
29 | Long: `print go files astview`,
30 | }
31 |
32 | var (
33 | astViewStdin bool
34 | astViewShowEndPos bool
35 | astViewShowTodo bool
36 | astViewOutline bool
37 | astViewShowTypeParams bool
38 | astViewSep string
39 | )
40 |
41 | func init() {
42 | Command.Flag.BoolVar(&astViewStdin, "stdin", false, "input from stdin")
43 | Command.Flag.BoolVar(&astViewShowEndPos, "end", false, "show decl end pos")
44 | Command.Flag.BoolVar(&astViewShowTodo, "todo", false, "show todo list")
45 | Command.Flag.BoolVar(&astViewShowTypeParams, "tp", false, "show typeparams")
46 | Command.Flag.BoolVar(&astViewOutline, "outline", false, "set outline mode")
47 | Command.Flag.StringVar(&astViewSep, "sep", ",", "set output seperator")
48 | }
49 |
50 | func runAstView(cmd *command.Command, args []string) error {
51 | if len(args) == 0 {
52 | cmd.Usage()
53 | return os.ErrInvalid
54 | }
55 | if astViewStdin {
56 | view, err := NewFilePackageSource(args[0], cmd.Stdin, true)
57 | if err != nil {
58 | return err
59 | }
60 | view.PrintTree(cmd.Stdout)
61 | } else {
62 | if len(args) == 1 && astViewOutline {
63 | err := PrintFileOutline(args[0], cmd.Stdout, astViewSep, true)
64 | if err != nil {
65 | return err
66 | }
67 | } else {
68 | err := PrintFilesTree(args, cmd.Stdout, true)
69 | if err != nil {
70 | return err
71 | }
72 | }
73 | }
74 | return nil
75 | }
76 |
77 | const (
78 | tag_package = "p"
79 | tag_imports_folder = "+m"
80 | tag_import = "mm"
81 | tag_type = "t"
82 | tag_struct = "s"
83 | tag_interface = "i"
84 | tag_value = "v"
85 | tag_const = "c"
86 | tag_func = "f"
87 | tag_value_folder = "+v"
88 | tag_const_folder = "+c"
89 | tag_func_folder = "+f"
90 | tag_factor_folder = "+tf"
91 | tag_type_method = "tm"
92 | tag_type_factor = "tf"
93 | tag_type_value = "tv"
94 | tag_todo = "b"
95 | tag_todo_folder = "+b"
96 | )
97 |
98 | type PackageView struct {
99 | fset *token.FileSet
100 | pdoc *PackageDoc
101 | pkg *ast.Package
102 | expr bool
103 | }
104 |
105 | var AllFiles []string
106 |
107 | func (p *PackageView) posFileIndex(pos token.Position) int {
108 | var index = -1
109 | for i := 0; i < len(AllFiles); i++ {
110 | if AllFiles[i] == pos.Filename {
111 | index = i
112 | break
113 | }
114 | }
115 | if index == -1 {
116 | AllFiles = append(AllFiles, pos.Filename)
117 | index = len(AllFiles) - 1
118 | }
119 | return index
120 | }
121 |
122 | func (p *PackageView) posText(node ast.Node) string {
123 | pos := p.fset.Position(node.Pos())
124 | index := p.posFileIndex(pos)
125 | if astViewShowEndPos {
126 | end := p.fset.Position(node.End())
127 | return fmt.Sprintf("%d:%d:%d:%d:%d", index, pos.Line, pos.Column, end.Line, end.Column)
128 | }
129 | return fmt.Sprintf("%d:%d:%d", index, pos.Line, pos.Column)
130 | }
131 |
132 | func NewFilePackage(filename string) (*PackageView, error) {
133 | p := new(PackageView)
134 | p.fset = token.NewFileSet()
135 | file, err := parser.ParseFile(p.fset, filename, nil, parser.AllErrors)
136 | if file == nil {
137 | return nil, err
138 | }
139 | m := make(map[string]*ast.File)
140 | m[filename] = file
141 | pkg, err := ast.NewPackage(p.fset, m, nil, nil)
142 | if err != nil {
143 | return nil, err
144 | }
145 | p.pkg = pkg
146 | p.pdoc = NewPackageDoc(pkg, pkg.Name, true)
147 | return p, nil
148 | }
149 |
150 | func NewPackageView(pkg *ast.Package, fset *token.FileSet, expr bool) (*PackageView, error) {
151 | p := new(PackageView)
152 | p.fset = fset
153 | p.pkg = pkg
154 | p.pdoc = NewPackageDoc(pkg, pkg.Name, true)
155 | p.expr = expr
156 | return p, nil
157 | }
158 |
159 | func ParseFiles(fset *token.FileSet, filenames []string, mode parser.Mode) (pkgs map[string]*ast.Package, pkgsfiles []string, first error) {
160 | pkgs = make(map[string]*ast.Package)
161 | for _, filename := range filenames {
162 | if src, err := parser.ParseFile(fset, filename, nil, mode); src != nil {
163 | name := src.Name.Name
164 | pkg, found := pkgs[name]
165 | if !found {
166 | pkg = &ast.Package{
167 | Name: name,
168 | Files: make(map[string]*ast.File),
169 | }
170 | pkgs[name] = pkg
171 | }
172 | pkg.Files[filename] = src
173 | pkgsfiles = append(pkgsfiles, filename)
174 | } else {
175 | first = err
176 | return
177 | }
178 | }
179 | return
180 | }
181 |
182 | func PrintFilesTree(filenames []string, w io.Writer, expr bool) error {
183 | fset := token.NewFileSet()
184 | mode := parser.AllErrors
185 | if astViewShowTodo {
186 | mode |= parser.ParseComments
187 | }
188 | pkgs, pkgsfiles, err := ParseFiles(fset, filenames, mode)
189 | if err != nil {
190 | return err
191 | }
192 | AllFiles = pkgsfiles
193 | for i := 0; i < len(AllFiles); i++ {
194 | fmt.Fprintf(w, "@%s\n", AllFiles[i])
195 | }
196 | for _, pkg := range pkgs {
197 | view, err := NewPackageView(pkg, fset, expr)
198 | if err != nil {
199 | return err
200 | }
201 | view.PrintTree(w)
202 | }
203 | return nil
204 | }
205 |
206 | func NewFilePackageSource(filename string, f io.Reader, expr bool) (*PackageView, error) {
207 | src, err := ioutil.ReadAll(f)
208 | if err != nil {
209 | return nil, err
210 | }
211 | p := new(PackageView)
212 | p.fset = token.NewFileSet()
213 | p.expr = expr
214 | mode := parser.AllErrors
215 | if astViewShowTodo {
216 | mode |= parser.ParseComments
217 | }
218 | file, err := parser.ParseFile(p.fset, filename, src, mode)
219 | if err != nil {
220 | return nil, err
221 | }
222 | m := make(map[string]*ast.File)
223 | m[filename] = file
224 | pkg, err := ast.NewPackage(p.fset, m, nil, nil)
225 | if err != nil {
226 | return nil, err
227 | }
228 |
229 | p.pdoc = NewPackageDoc(pkg, pkg.Name, true)
230 | return p, nil
231 | }
232 |
233 | func (p *PackageView) out0(w io.Writer, level int, text ...string) {
234 | fmt.Fprintf(w, "%v%s%s\n", level, astViewSep, strings.Join(text, astViewSep))
235 | }
236 | func (p *PackageView) out1(w io.Writer, level int, pos ast.Node, text ...string) {
237 | fmt.Fprintf(w, "%v%s%s%s%s\n", level, astViewSep, strings.Join(text, astViewSep), astViewSep, p.posText(pos))
238 | }
239 | func (p *PackageView) out2(w io.Writer, level int, pos ast.Node, expr ast.Expr, text ...string) {
240 | fmt.Fprintf(w, "%v%s%s%s%s@%v\n", level, astViewSep, strings.Join(text, astViewSep), astViewSep, p.posText(pos), types.ExprString(expr))
241 | }
242 | func (p *PackageView) out2s(w io.Writer, level int, pos ast.Node, expr string, text ...string) {
243 | fmt.Fprintf(w, "%v%s%s%s%s@%v\n", level, astViewSep, strings.Join(text, astViewSep), astViewSep, p.posText(pos), expr)
244 | }
245 |
246 | func (p *PackageView) printFuncsHelper(w io.Writer, funcs []*FuncDoc, level int, tag string, tag_folder string) {
247 | for _, f := range funcs {
248 | if p.expr {
249 | p.out2(w, level, f.Decl, f.Decl.Type, tag, funcName(f.Decl, astViewShowTypeParams))
250 | } else {
251 | p.out1(w, level, f.Decl, tag, funcName(f.Decl, astViewShowTypeParams))
252 | }
253 | }
254 | }
255 |
256 | func (p *PackageView) PrintVars(w io.Writer, vars []*ValueDoc, level int, tag string, tag_folder string) {
257 | if len(tag_folder) > 0 && len(vars) > 0 {
258 | if tag_folder == tag_value_folder {
259 | p.out0(w, level, tag_folder, "Variables")
260 | } else if tag_folder == tag_const_folder {
261 | p.out0(w, level, tag_folder, "Constants")
262 | }
263 | level++
264 | }
265 | for _, v := range vars {
266 | if v.Decl == nil {
267 | continue
268 | }
269 | for _, s := range v.Decl.Specs {
270 | if m, ok := s.(*ast.ValueSpec); ok {
271 | for i := 0; i < len(m.Names); i++ {
272 | if p.expr && m.Type != nil {
273 | p.out2(w, level, m, m.Type, tag, m.Names[i].String())
274 | } else {
275 | p.out1(w, level, m, tag, m.Names[i].String())
276 | }
277 | }
278 | }
279 | }
280 | }
281 | }
282 | func (p *PackageView) PrintTypes(w io.Writer, types []*TypeDoc, level int) {
283 | for _, d := range types {
284 | if d.Decl == nil {
285 | continue
286 | }
287 | typespec := d.Decl.Specs[0].(*ast.TypeSpec)
288 | var tag = tag_type
289 | if _, ok := typespec.Type.(*ast.InterfaceType); ok {
290 | tag = tag_interface
291 | } else if _, ok := typespec.Type.(*ast.StructType); ok {
292 | tag = tag_struct
293 | }
294 | p.out1(w, level, d.Decl, tag, typeName(typespec, astViewShowTypeParams))
295 | p.printFuncsHelper(w, d.Funcs, level+1, tag_type_factor, "")
296 | p.printFuncsHelper(w, d.Methods, level+1, tag_type_method, "")
297 | p.PrintTypeFields(w, d.Decl, level+1)
298 | //p.PrintVars(w, d.Consts, level+1, tag_const, "")
299 | //p.PrintVars(w, d.Vars, level+1, tag_value, "")
300 | }
301 | }
302 |
303 | func (p *PackageView) PrintTypeFields(w io.Writer, decl *ast.GenDecl, level int) {
304 | spec, ok := decl.Specs[0].(*ast.TypeSpec)
305 | if ok == false {
306 | return
307 | }
308 | switch d := spec.Type.(type) {
309 | case *ast.StructType:
310 | for _, field := range d.Fields.List {
311 | if field.Names == nil {
312 | p.out2(w, level, field, field.Type, tag_type, types.ExprString(field.Type))
313 | } else {
314 | for _, m := range field.Names {
315 | if field.Type != nil {
316 | p.out2(w, level, field, field.Type, tag_type_value, m.Name)
317 | } else {
318 | p.out1(w, level, field, tag_type_value, m.Name)
319 | }
320 | }
321 | }
322 | }
323 | case *ast.InterfaceType:
324 | for _, list := range d.Methods.List {
325 | if len(list.Names) == 0 {
326 | p.out2(w, level, list, list.Type, tag_type, types.ExprString(list.Type))
327 | } else {
328 | for _, m := range list.Names {
329 | p.out2(w, level, list.Type, m, tag_type_method, m.Name)
330 | }
331 | }
332 | }
333 | }
334 | }
335 |
336 | func (p *PackageView) PrintHeader(w io.Writer, level int) {
337 | p.out0(w, level, tag_package, p.pdoc.PackageName)
338 | }
339 |
340 | func (p *PackageView) PrintImports(w io.Writer, level int, tag, tag_folder string) {
341 | if tag_folder != "" && len(p.pdoc.Imports) > 0 {
342 | p.out0(w, level, tag_folder, "Imports")
343 | level++
344 | }
345 | var parentPkg *pkgutil.Package
346 | if pkgutil.IsVendorExperiment() && p.pkg != nil {
347 | for filename, _ := range p.pkg.Files {
348 | if !filepath.IsAbs(filename) {
349 | name, err := filepath.Abs(filename)
350 | if err == nil {
351 | filename = name
352 | }
353 | }
354 | parentPkg = pkgutil.ImportFile(filename)
355 | break
356 | }
357 | }
358 | for _, name := range p.pdoc.Imports {
359 | vname := "\"" + name + "\""
360 | var ps []string
361 | for _, file := range p.pkg.Files {
362 | for _, v := range file.Imports {
363 | if v.Path.Value == vname {
364 | ps = append(ps, p.posText(v))
365 | }
366 | }
367 | }
368 | if parentPkg != nil {
369 | name, _ = pkgutil.VendoredImportPath(parentPkg, name)
370 | }
371 | p.out0(w, level, tag, name, strings.Join(ps, ";"))
372 | }
373 | }
374 |
375 | func (p *PackageView) PrintFuncs(w io.Writer, level int, tag_folder string) {
376 | hasFolder := false
377 | if len(p.pdoc.Funcs) > 0 || len(p.pdoc.Factorys) > 0 {
378 | hasFolder = true
379 | }
380 | if !hasFolder {
381 | return
382 | }
383 | if len(tag_folder) > 0 {
384 | p.out0(w, level, tag_folder, "Functions")
385 | level++
386 | }
387 | p.printFuncsHelper(w, p.pdoc.Factorys, level, tag_type_factor, tag_func_folder)
388 | p.printFuncsHelper(w, p.pdoc.Funcs, level, tag_func, tag_func_folder)
389 | }
390 |
391 | func (p *PackageView) PrintTodos(w io.Writer, level int, tag, tag_folder string) {
392 | hasFolder := false
393 | if len(p.pdoc.Todos) > 0 {
394 | hasFolder = true
395 | }
396 | if !hasFolder {
397 | return
398 | }
399 | if len(tag_folder) > 0 {
400 | p.out0(w, level, tag_folder, "TodoList")
401 | level++
402 | }
403 | for _, todo := range p.pdoc.Todos {
404 | c := todo.Comments.List[0]
405 | p.out2s(w, level, c, todo.Text, tag, todo.Tag)
406 | }
407 | }
408 |
409 | func (p *PackageView) PrintPackage(w io.Writer, level int) {
410 | p.PrintHeader(w, level)
411 | level++
412 | p.PrintImports(w, level, tag_import, tag_imports_folder)
413 | p.PrintVars(w, p.pdoc.Vars, level, tag_value, tag_value_folder)
414 | p.PrintVars(w, p.pdoc.Consts, level, tag_const, tag_const_folder)
415 | p.PrintFuncs(w, level, tag_func_folder)
416 | p.PrintTypes(w, p.pdoc.Types, level)
417 | p.PrintTodos(w, level, tag_todo, tag_todo_folder)
418 | }
419 |
420 | // level,tag,pos@info
421 | func (p *PackageView) PrintTree(w io.Writer) {
422 | p.PrintPackage(w, 0)
423 | }
424 |
425 | // level,tag,pos@info
426 | func PrintFileOutline(filename string, w io.Writer, sep string, showexpr bool) error {
427 | fset := token.NewFileSet()
428 | mode := parser.AllErrors
429 | if astViewShowTodo {
430 | mode |= parser.ParseComments
431 | }
432 | f, err := parser.ParseFile(fset, filename, nil, mode)
433 | if err != nil {
434 | return err
435 | }
436 | posText := func(node ast.Node) string {
437 | pos := fset.Position(node.Pos())
438 | if astViewShowEndPos {
439 | end := fset.Position(node.End())
440 | return fmt.Sprintf("%d:%d:%d:%d:%d", 0, pos.Line, pos.Column, end.Line, end.Column)
441 | }
442 | return fmt.Sprintf("%d:%d:%d", 0, pos.Line, pos.Column)
443 | }
444 |
445 | out0 := func(level int, text ...string) {
446 | fmt.Fprintf(w, "%v%s%s\n", level, sep, strings.Join(text, sep))
447 | }
448 | out1 := func(level int, pos ast.Node, text ...string) {
449 | fmt.Fprintf(w, "%v%s%s%s%s\n", level, sep, strings.Join(text, sep), sep, posText(pos))
450 | }
451 | out2 := func(level int, pos ast.Node, expr ast.Expr, text ...string) {
452 | fmt.Fprintf(w, "%v%s%s%s%s@%v\n", level, sep, strings.Join(text, sep), sep, posText(pos), types.ExprString(expr))
453 | }
454 | out2s := func(level int, pos ast.Node, expr string, text ...string) {
455 | fmt.Fprintf(w, "%v%s%s%s%s@%v\n", level, sep, strings.Join(text, sep), sep, posText(pos), expr)
456 | }
457 |
458 | fmt.Fprintf(w, "@%s\n", filename)
459 | level := 0
460 | out1(level, f.Name, tag_package, f.Name.Name)
461 | // level++
462 | if len(f.Imports) > 0 {
463 | sort.Slice(f.Imports, func(i, j int) bool {
464 | return f.Imports[i].Pos() < f.Imports[j].Pos()
465 | })
466 | out0(level, tag_imports_folder, "Imports")
467 | level++
468 | for _, imp := range f.Imports {
469 | path, _ := strconv.Unquote(imp.Path.Value)
470 | out1(level, imp, tag_import, path)
471 | }
472 | level--
473 | }
474 |
475 | sort.Slice(f.Decls, func(i, j int) bool {
476 | return f.Decls[i].Pos() < f.Decls[j].Pos()
477 | })
478 | for _, decl := range f.Decls {
479 | switch d := decl.(type) {
480 | case *ast.GenDecl:
481 | switch d.Tok {
482 | case token.IMPORT:
483 | case token.TYPE:
484 | for _, spec := range d.Specs {
485 | ts := spec.(*ast.TypeSpec)
486 | switch t := ts.Type.(type) {
487 | case *ast.StructType:
488 | out2(level, ts, t, tag_struct, typeName(ts, astViewShowTypeParams))
489 | level++
490 | for _, f := range t.Fields.List {
491 | for _, name := range f.Names {
492 | out2(level, f, f.Type, tag_type_value, name.String())
493 | }
494 | }
495 | level--
496 | case *ast.InterfaceType:
497 | out2(level, ts, t, tag_interface, typeName(ts, astViewShowTypeParams))
498 | level++
499 | for _, f := range t.Methods.List {
500 | if len(f.Names) != 0 {
501 | for _, name := range f.Names {
502 | out2(level, f, f.Type, tag_type_method, name.String())
503 | }
504 | } else {
505 | out2(level, f, f.Type, tag_type, types.ExprString(f.Type))
506 | }
507 | }
508 | level--
509 | default:
510 | out2(level, ts, t, tag_type, typeName(ts, astViewShowTypeParams))
511 | }
512 | }
513 | case token.CONST:
514 | for _, spec := range d.Specs {
515 | vs := spec.(*ast.ValueSpec)
516 | for i, name := range vs.Names {
517 | if vs.Values == nil {
518 | out1(level, vs, tag_const, name.String())
519 | } else {
520 | out2(level, vs, vs.Values[i], tag_const, name.String())
521 | }
522 | }
523 | }
524 | case token.VAR:
525 | for _, spec := range d.Specs {
526 | vs := spec.(*ast.ValueSpec)
527 | for _, name := range vs.Names {
528 | if vs.Type == nil {
529 | out1(level, vs, tag_value, name.String())
530 | } else {
531 | out2(level, vs, vs.Type, tag_value, name.String())
532 | }
533 | }
534 | }
535 | }
536 | case *ast.FuncDecl:
537 | if d.Recv != nil {
538 | var name string
539 | if astViewShowTypeParams {
540 | name = types.ExprString(d.Recv.List[0].Type)
541 | } else {
542 | var star bool
543 | name, star = recvTypeName(d.Recv.List[0].Type, true)
544 | if star {
545 | name = "*" + name
546 | }
547 | }
548 | out2(level, d, d.Type, tag_func, "("+name+")."+d.Name.String())
549 | } else {
550 | out2(level, d, d.Type, tag_func, funcName(d, astViewShowTypeParams))
551 | }
552 | }
553 | }
554 |
555 | if astViewShowTodo {
556 | var todoList []*TodoDoc
557 | for _, c := range f.Comments {
558 | text := c.List[0].Text
559 | if m := todo_markers.FindStringSubmatchIndex(text); m != nil {
560 | todoList = append(todoList, &TodoDoc{text[m[2]:m[3]], text[m[2]:], c})
561 | }
562 | }
563 | if len(todoList) > 0 {
564 | out0(level, tag_todo_folder, "TodoList")
565 | level++
566 | for _, todo := range todoList {
567 | c := todo.Comments.List[0]
568 | out2s(level, c, todo.Text, tag_todo, todo.Tag)
569 | }
570 | level--
571 | }
572 | }
573 | return nil
574 | }
575 |
--------------------------------------------------------------------------------
/finddoc/finddoc.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The rspace Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Doc is a simple document printer that produces the doc comments for its
6 | // argument symbols, plus a link to the full documentation and a pointer to
7 | // the source. It has a more Go-like UI than godoc. It can also search for
8 | // symbols by looking in all packages, and case is ignored. For instance:
9 | // doc isupper
10 | // will find unicode.IsUpper.
11 | //
12 | // The -pkg flag retrieves package-level doc comments only.
13 | //
14 | // Usage:
15 | // doc pkg.name # "doc io.Writer"
16 | // doc pkg name # "doc fmt Printf"
17 | // doc name # "doc isupper" (finds unicode.IsUpper)
18 | // doc -pkg pkg # "doc fmt"
19 | //
20 | // The pkg is the last element of the package path;
21 | // no slashes (ast.Node not go/ast.Node).
22 | //
23 | // Flags
24 | // -c(onst) -f(unc) -i(nterface) -m(ethod) -s(truct) -t(ype) -v(ar)
25 | // restrict hits to declarations of the corresponding kind.
26 | // Flags
27 | // -doc -src -url
28 | // restrict printing to the documentation, source path, or godoc URL.
29 | package finddoc
30 |
31 | import (
32 | "bytes"
33 | "fmt"
34 | "go/ast"
35 | "go/parser"
36 | "go/printer"
37 | "go/token"
38 | "go/types"
39 | "os"
40 | "path"
41 | "path/filepath"
42 | "regexp"
43 | "runtime"
44 | "strings"
45 |
46 | "github.com/visualfc/gotools/pkg/command"
47 | )
48 |
49 | const usageDoc = `Find documentation for names.
50 | usage:
51 | doc pkg.name # "doc io.Writer"
52 | doc pkg name # "doc fmt Printf"
53 | doc name # "doc isupper" finds unicode.IsUpper
54 | doc -pkg pkg # "doc fmt"
55 | doc -r expr # "doc -r '.*exported'"
56 | pkg is the last component of any package, e.g. fmt, parser
57 | name is the name of an exported symbol; case is ignored in matches.
58 |
59 | The name may also be a regular expression to select which names
60 | to match. In regular expression searches, case is ignored and
61 | the pattern must match the entire name, so ".?print" will match
62 | Print, Fprint and Sprint but not Fprintf.
63 |
64 | Flags
65 | -c(onst) -f(unc) -i(nterface) -m(ethod) -s(truct) -t(ype) -v(ar)
66 | restrict hits to declarations of the corresponding kind.
67 | Flags
68 | -doc -src -url
69 | restrict printing to the documentation, source path, or godoc URL.
70 | Flag
71 | -r
72 | takes a single argument (no package), a name or regular expression
73 | to search for in all packages.
74 | `
75 |
76 | var Command = &command.Command{
77 | Run: runDoc,
78 | UsageLine: "finddoc [pkg.name|pkg name|-pkg name]",
79 | Short: "golang doc lookup",
80 | Long: usageDoc,
81 | }
82 |
83 | var (
84 | // If none is set, all are set.
85 | docFlag bool
86 | srcFlag bool
87 | urlFlag bool
88 | regexpFlag bool
89 | matchWordFlag bool
90 | matchCaseFlag bool
91 | constantFlag bool
92 | functionFlag bool
93 | interfaceFlag bool
94 | methodFlag bool
95 | packageFlag bool
96 | structFlag bool
97 | typeFlag bool
98 | variableFlag bool
99 | urlHeadTag string
100 | )
101 |
102 | func init() {
103 | Command.Flag.BoolVar(&docFlag, "doc", false, "restrict output to documentation only")
104 | Command.Flag.BoolVar(&srcFlag, "src", false, "restrict output to source file only")
105 | Command.Flag.BoolVar(&urlFlag, "url", false, "restrict output to godoc URL only")
106 | Command.Flag.BoolVar(®expFlag, "r", false, "single argument is a regular expression for a name")
107 | Command.Flag.BoolVar(&matchWordFlag, "word", false, "search match whole word")
108 | Command.Flag.BoolVar(&matchCaseFlag, "case", false, "search match case")
109 |
110 | Command.Flag.BoolVar(&constantFlag, "const", false, "show doc for consts only")
111 | Command.Flag.BoolVar(&functionFlag, "func", false, "show doc for funcs only")
112 | Command.Flag.BoolVar(&interfaceFlag, "interface", false, "show doc for interfaces only")
113 | Command.Flag.BoolVar(&methodFlag, "method", false, "show doc for methods only")
114 | Command.Flag.BoolVar(&packageFlag, "package", false, "show top-level package doc only")
115 | Command.Flag.BoolVar(&structFlag, "struct", false, "show doc for structs only")
116 | Command.Flag.BoolVar(&typeFlag, "type", false, "show doc for types only")
117 | Command.Flag.BoolVar(&variableFlag, "var", false, "show doc for vars only")
118 |
119 | Command.Flag.BoolVar(&constantFlag, "c", false, "alias for -const")
120 | Command.Flag.BoolVar(&functionFlag, "f", false, "alias for -func")
121 | Command.Flag.BoolVar(&interfaceFlag, "i", false, "alias for -interface")
122 | Command.Flag.BoolVar(&methodFlag, "m", false, "alias for -method")
123 | Command.Flag.BoolVar(&packageFlag, "pkg", false, "alias for -package")
124 | Command.Flag.BoolVar(&structFlag, "s", false, "alias for -struct")
125 | Command.Flag.BoolVar(&typeFlag, "t", false, "alias for -type")
126 | Command.Flag.BoolVar(&variableFlag, "v", false, "alias for -var")
127 |
128 | Command.Flag.StringVar(&urlHeadTag, "urltag", "", "url head tag, liteide provate")
129 | }
130 |
131 | func runDoc(cmd *command.Command, args []string) error {
132 | if !(constantFlag || functionFlag || interfaceFlag || methodFlag || packageFlag || structFlag || typeFlag || variableFlag) { // none set
133 | constantFlag = true
134 | functionFlag = true
135 | methodFlag = true
136 | // Not package! It's special.
137 | typeFlag = true
138 | variableFlag = true
139 | }
140 | if !(docFlag || srcFlag || urlFlag) {
141 | docFlag = true
142 | srcFlag = true
143 | urlFlag = true
144 | }
145 | var pkg, name string
146 | switch len(args) {
147 | case 1:
148 | if packageFlag {
149 | pkg = args[0]
150 | } else if regexpFlag {
151 | name = args[0]
152 | } else if strings.Contains(args[0], ".") {
153 | pkg, name = split(args[0])
154 | } else {
155 | name = args[0]
156 | }
157 | case 2:
158 | if packageFlag {
159 | cmd.Usage()
160 | return os.ErrInvalid
161 | }
162 | pkg, name = args[0], args[1]
163 | default:
164 | cmd.Usage()
165 | return os.ErrInvalid
166 | }
167 | if strings.Contains(pkg, "/") {
168 | fmt.Fprintf(os.Stderr, "doc: package name cannot contain slash (TODO)\n")
169 | os.Exit(2)
170 | }
171 | for _, path := range Paths(pkg) {
172 | lookInDirectory(path, name)
173 | }
174 | return nil
175 | }
176 |
177 | var slash = string(filepath.Separator)
178 | var slashDot = string(filepath.Separator) + "."
179 | var goRootSrcPkg = filepath.Join(runtime.GOROOT(), "src", "pkg")
180 | var goRootSrcCmd = filepath.Join(runtime.GOROOT(), "src", "cmd")
181 | var goPaths = SplitGopath()
182 |
183 | func split(arg string) (pkg, name string) {
184 | dot := strings.IndexRune(arg, '.') // We know there's one there.
185 | return arg[0:dot], arg[dot+1:]
186 | }
187 |
188 | func Paths(pkg string) []string {
189 | pkgs := pathsFor(runtime.GOROOT(), pkg)
190 | for _, root := range goPaths {
191 | pkgs = append(pkgs, pathsFor(root, pkg)...)
192 | }
193 | return pkgs
194 | }
195 |
196 | func SplitGopath() []string {
197 | gopath := os.Getenv("GOPATH")
198 | if gopath == "" {
199 | return nil
200 | }
201 | return strings.Split(gopath, string(os.PathListSeparator))
202 | }
203 |
204 | // pathsFor recursively walks the tree looking for possible directories for the package:
205 | // those whose basename is pkg.
206 | func pathsFor(root, pkg string) []string {
207 | root = path.Join(root, "src")
208 | pkgPaths := make([]string, 0, 10)
209 | visit := func(pathName string, f os.FileInfo, err error) error {
210 | if err != nil {
211 | return nil
212 | }
213 | // One package per directory. Ignore the files themselves.
214 | if !f.IsDir() {
215 | return nil
216 | }
217 | // No .hg or other dot nonsense please.
218 | if strings.Contains(pathName, slashDot) {
219 | return filepath.SkipDir
220 | }
221 | // Is the last element of the path correct
222 | if pkg == "" || filepath.Base(pathName) == pkg {
223 | pkgPaths = append(pkgPaths, pathName)
224 | }
225 | return nil
226 | }
227 |
228 | filepath.Walk(root, visit)
229 | return pkgPaths
230 | }
231 |
232 | // lookInDirectory looks in the package (if any) in the directory for the named exported identifier.
233 | func lookInDirectory(directory, name string) {
234 | fset := token.NewFileSet()
235 | pkgs, _ := parser.ParseDir(fset, directory, nil, parser.ParseComments) // Ignore the error.
236 | for _, pkg := range pkgs {
237 | if pkg.Name == "main" || strings.HasSuffix(pkg.Name, "_test") {
238 | continue
239 | }
240 | doPackage(pkg, fset, name)
241 | }
242 | }
243 |
244 | // prefixDirectory places the directory name on the beginning of each name in the list.
245 | func prefixDirectory(directory string, names []string) {
246 | if directory != "." {
247 | for i, name := range names {
248 | names[i] = filepath.Join(directory, name)
249 | }
250 | }
251 | }
252 |
253 | // File is a wrapper for the state of a file used in the parser.
254 | // The parse tree walkers are all methods of this type.
255 | type File struct {
256 | fset *token.FileSet
257 | name string // Name of file.
258 | ident string // Identifier we are searching for.
259 | lowerIdent string // lower ident
260 | regexp *regexp.Regexp
261 | pathPrefix string // Prefix from GOROOT/GOPATH.
262 | urlPrefix string // Start of corresponding URL for golang.org or godoc.org.
263 | file *ast.File
264 | comments ast.CommentMap
265 | defs map[*ast.Ident]types.Object
266 | doPrint bool
267 | found bool
268 | allFiles []*File // All files in the package.
269 | }
270 |
271 | // doPackage analyzes the single package constructed from the named files, looking for
272 | // the definition of ident.
273 | func doPackage(pkg *ast.Package, fset *token.FileSet, ident string) {
274 | var files []*File
275 | found := false
276 | for name, astFile := range pkg.Files {
277 | if packageFlag && astFile.Doc == nil {
278 | continue
279 | }
280 | file := &File{
281 | fset: fset,
282 | name: name,
283 | ident: ident,
284 | lowerIdent: strings.ToLower(ident),
285 | file: astFile,
286 | comments: ast.NewCommentMap(fset, astFile, astFile.Comments),
287 | }
288 | if regexpFlag && regexp.QuoteMeta(ident) != ident {
289 | // It's a regular expression.
290 | var err error
291 | file.regexp, err = regexp.Compile("^(?i:" + ident + ")$")
292 | if err != nil {
293 | fmt.Fprintf(os.Stderr, "regular expression `%s`:", err)
294 | os.Exit(2)
295 | }
296 | }
297 | switch {
298 | case strings.HasPrefix(name, goRootSrcPkg):
299 | file.urlPrefix = "http://golang.org/pkg"
300 | file.pathPrefix = goRootSrcPkg
301 | case strings.HasPrefix(name, goRootSrcCmd):
302 | file.urlPrefix = "http://golang.org/cmd"
303 | file.pathPrefix = goRootSrcCmd
304 | default:
305 | file.urlPrefix = "http://godoc.org"
306 | for _, path := range goPaths {
307 | p := filepath.Join(path, "src")
308 | if strings.HasPrefix(name, p) {
309 | file.pathPrefix = p
310 | break
311 | }
312 | }
313 | }
314 | file.urlPrefix = urlHeadTag + file.urlPrefix
315 | files = append(files, file)
316 | if found {
317 | continue
318 | }
319 | file.doPrint = false
320 | if packageFlag {
321 | file.pkgComments()
322 | } else {
323 | ast.Walk(file, file.file)
324 | if file.found {
325 | found = true
326 | }
327 | }
328 | }
329 |
330 | if !found {
331 | return
332 | }
333 |
334 | // By providing the Context with our own error function, it will continue
335 | // past the first error. There is no need for that function to do anything.
336 | config := types.Config{
337 | Error: func(error) {},
338 | }
339 | info := &types.Info{
340 | Defs: make(map[*ast.Ident]types.Object),
341 | }
342 | path := ""
343 | var astFiles []*ast.File
344 | for name, astFile := range pkg.Files {
345 | if path == "" {
346 | path = name
347 | }
348 | astFiles = append(astFiles, astFile)
349 | }
350 | config.Check(path, fset, astFiles, info) // Ignore errors.
351 |
352 | // We need to search all files for methods, so record the full list in each file.
353 | for _, file := range files {
354 | file.allFiles = files
355 | }
356 | for _, file := range files {
357 | file.doPrint = true
358 | file.defs = info.Defs
359 | if packageFlag {
360 | file.pkgComments()
361 | } else {
362 | ast.Walk(file, file.file)
363 | }
364 | }
365 | }
366 |
367 | // Visit implements the ast.Visitor interface.
368 | func (f *File) Visit(node ast.Node) ast.Visitor {
369 | switch n := node.(type) {
370 | case *ast.GenDecl:
371 | // Variables, constants, types.
372 | for _, spec := range n.Specs {
373 | switch spec := spec.(type) {
374 | case *ast.ValueSpec:
375 | if constantFlag && n.Tok == token.CONST || variableFlag && n.Tok == token.VAR {
376 | for _, ident := range spec.Names {
377 | if f.match(ident.Name) {
378 | f.printNode(n, ident, f.nameURL(ident.Name))
379 | break
380 | }
381 | }
382 | }
383 | case *ast.TypeSpec:
384 | // If there is only one Spec, there are probably no parens and the
385 | // comment we want appears before the type keyword, bound to
386 | // the GenDecl. If the Specs are parenthesized, the comment we want
387 | // is bound to the Spec. Hence we dig into the GenDecl to the Spec,
388 | // but only if there are no parens.
389 | node := ast.Node(n)
390 | if n.Lparen.IsValid() {
391 | node = spec
392 | }
393 | if f.match(spec.Name.Name) {
394 | if typeFlag {
395 | f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
396 | } else {
397 | switch spec.Type.(type) {
398 | case *ast.InterfaceType:
399 | if interfaceFlag {
400 | f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
401 | }
402 | case *ast.StructType:
403 | if structFlag {
404 | f.printNode(node, spec.Name, f.nameURL(spec.Name.Name))
405 | }
406 | }
407 | }
408 | if f.doPrint && f.defs[spec.Name] != nil && f.defs[spec.Name].Type() != nil {
409 | ms := types.NewMethodSet(f.defs[spec.Name].Type()) //.Type().MethodSet()
410 | if ms.Len() == 0 {
411 | ms = types.NewMethodSet(types.NewPointer(f.defs[spec.Name].Type())) //.MethodSet()
412 | }
413 | f.methodSet(ms)
414 | }
415 | }
416 | case *ast.ImportSpec:
417 | continue // Don't care.
418 | }
419 | }
420 | case *ast.FuncDecl:
421 | // Methods, top-level functions.
422 | if f.match(n.Name.Name) {
423 | n.Body = nil // Do not print the function body.
424 | if methodFlag && n.Recv != nil {
425 | f.printNode(n, n.Name, f.methodURL(n.Recv.List[0].Type, n.Name.Name))
426 | } else if functionFlag && n.Recv == nil {
427 | f.printNode(n, n.Name, f.nameURL(n.Name.Name))
428 | }
429 | }
430 | }
431 | return f
432 | }
433 |
434 | func (f *File) match(name string) bool {
435 | // name must be exported.
436 | if !ast.IsExported(name) {
437 | return false
438 | }
439 | if f.regexp == nil {
440 | if matchWordFlag {
441 | if matchCaseFlag {
442 | return name == f.ident
443 | }
444 | return strings.ToLower(name) == f.lowerIdent
445 | } else {
446 | if matchCaseFlag {
447 | return strings.Contains(name, f.ident)
448 | }
449 | return strings.Contains(strings.ToLower(name), f.lowerIdent)
450 | }
451 | }
452 | return f.regexp.MatchString(name)
453 | }
454 |
455 | func (f *File) printNode(node, ident ast.Node, url string) {
456 | if !f.doPrint {
457 | f.found = true
458 | return
459 | }
460 | fmt.Printf("%s%s%s", url, f.sourcePos(f.fset.Position(ident.Pos())), f.docs(node))
461 | }
462 |
463 | func (f *File) docs(node ast.Node) []byte {
464 | if !docFlag {
465 | return nil
466 | }
467 | commentedNode := printer.CommentedNode{Node: node}
468 | if comments := f.comments.Filter(node).Comments(); comments != nil {
469 | commentedNode.Comments = comments
470 | }
471 | var b bytes.Buffer
472 | printer.Fprint(&b, f.fset, &commentedNode)
473 | b.Write([]byte("\n\n")) // Add a blank line between entries if we print documentation.
474 | return b.Bytes()
475 | }
476 |
477 | func (f *File) pkgComments() {
478 | doc := f.file.Doc
479 | if doc == nil {
480 | return
481 | }
482 | url := ""
483 | if urlFlag {
484 | url = f.packageURL() + "\n"
485 | }
486 | docText := ""
487 | if docFlag {
488 | docText = fmt.Sprintf("package %s\n%s\n\n", f.file.Name.Name, doc.Text())
489 | }
490 | fmt.Printf("%s%s%s", url, f.sourcePos(f.fset.Position(doc.Pos())), docText)
491 | }
492 |
493 | func (f *File) packageURL() string {
494 | s := strings.TrimPrefix(f.name, f.pathPrefix)
495 | // Now we have a path with a final file name. Drop it.
496 | if i := strings.LastIndex(s, slash); i > 0 {
497 | s = s[:i+1]
498 | }
499 | return f.urlPrefix + s
500 | }
501 |
502 | func (f *File) packageName() string {
503 | s := strings.TrimPrefix(f.name, f.pathPrefix)
504 | // Now we have a path with a final file name. Drop it.
505 | if i := strings.LastIndex(s, slash); i > 0 {
506 | s = s[:i+1]
507 | }
508 | s = strings.Trim(s, slash)
509 | return filepath.ToSlash(s)
510 | }
511 |
512 | func (f *File) sourcePos(posn token.Position) string {
513 | if !srcFlag {
514 | return ""
515 | }
516 | return fmt.Sprintf("%s:%d:\n", posn.Filename, posn.Line)
517 | }
518 |
519 | func (f *File) nameURL(name string) string {
520 | if !urlFlag {
521 | return ""
522 | }
523 | return fmt.Sprintf("%s#%s\n", f.packageURL(), name)
524 | }
525 |
526 | func (f *File) methodURL(typ ast.Expr, name string) string {
527 | if !urlFlag {
528 | return ""
529 | }
530 | var b bytes.Buffer
531 | printer.Fprint(&b, f.fset, typ)
532 | typeName := b.Bytes()
533 | if len(typeName) > 0 && typeName[0] == '*' {
534 | typeName = typeName[1:]
535 | }
536 | return fmt.Sprintf("%s#%s.%s\n", f.packageURL(), typeName, name)
537 | }
538 |
539 | // Here follows the code to find and print a method (actually a method set, because
540 | // we want to do only one redundant tree walk, not one per method).
541 | // It should be much easier than walking the whole tree again, but that's what we must do.
542 | // TODO.
543 |
544 | type method struct {
545 | index int // Which doc to write. (Keeps the results sorted)
546 | *types.Selection
547 | }
548 |
549 | type methodVisitor struct {
550 | *File
551 | methods []method
552 | docs []string
553 | }
554 |
555 | func (f *File) methodSet(set *types.MethodSet) {
556 | // Build the set of things we're looking for.
557 | methods := make([]method, 0, set.Len())
558 | docs := make([]string, set.Len())
559 | for i := 0; i < set.Len(); i++ {
560 | if ast.IsExported(set.At(i).Obj().Name()) {
561 | m := method{
562 | i,
563 | set.At(i),
564 | }
565 | methods = append(methods, m)
566 | }
567 | }
568 | if len(methods) == 0 {
569 | return
570 | }
571 | // Collect the docs.
572 | for _, file := range f.allFiles {
573 | visitor := &methodVisitor{
574 | File: file,
575 | methods: methods,
576 | docs: docs,
577 | }
578 | ast.Walk(visitor, file.file)
579 | methods = visitor.methods
580 | }
581 | // Print them in order. The incoming method set is sorted by name.
582 | for _, doc := range docs {
583 | if doc != "" {
584 | fmt.Print(doc)
585 | }
586 | }
587 | }
588 |
589 | // Visit implements the ast.Visitor interface.
590 | func (visitor *methodVisitor) Visit(node ast.Node) ast.Visitor {
591 | switch n := node.(type) {
592 | case *ast.FuncDecl:
593 | for i, method := range visitor.methods {
594 | // If this is the right one, the position of the name of its identifier will match.
595 | if method.Obj().Pos() == n.Name.Pos() {
596 | n.Body = nil // TODO. Ugly - don't print the function body.
597 | visitor.docs[method.index] = fmt.Sprintf("%s", visitor.File.docs(n))
598 | // If this was the last method, we're done.
599 | if len(visitor.methods) == 1 {
600 | return nil
601 | }
602 | // Drop this one from the list.
603 | visitor.methods = append(visitor.methods[:i], visitor.methods[i+1:]...)
604 | return visitor
605 | }
606 | }
607 | }
608 | return visitor
609 | }
610 |
--------------------------------------------------------------------------------