Repository: robertkrimen/godocdown
Branch: master
Commit: 0bfa04905481
Files: 38
Total size: 98.4 KB
Directory structure:
gitextract_lium6a1f/
├── .gitignore
├── Makefile
├── README.markdown
├── example/
│ ├── .godocdown.markdown
│ └── example.go
├── example.markdown
├── example.template
├── godocdown/
│ ├── .test/
│ │ ├── godocdown.markdown/
│ │ │ ├── .godocdown.markdown
│ │ │ ├── .godocdown.md
│ │ │ ├── .godocdown.template
│ │ │ └── .godocdown.tmpl
│ │ ├── godocdown.md/
│ │ │ ├── .godocdown.md
│ │ │ ├── .godocdown.template
│ │ │ └── .godocdown.tmpl
│ │ ├── godocdown.template/
│ │ │ ├── .godocdown.template
│ │ │ └── .godocdown.tmpl
│ │ ├── godocdown.tmpl/
│ │ │ └── .godocdown.tmpl
│ │ └── issue3/
│ │ └── issue3.go
│ ├── 7f_shim
│ ├── Makefile
│ ├── README.markdown
│ ├── dbg/
│ │ └── dbg.go
│ ├── dbg.go
│ ├── go_doc_totext.go
│ ├── kilt/
│ │ ├── at.go
│ │ ├── exec_command.go
│ │ ├── grave_trim.go
│ │ ├── kilt.go
│ │ ├── print_defaults.go
│ │ ├── sha1.go
│ │ ├── symlink.go
│ │ └── write_atomic_file.go
│ ├── kilt.go
│ ├── main.go
│ ├── main_test.go
│ ├── render.go
│ └── terst/
│ └── terst.go
└── godocdown.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/godocdown/godocdown
================================================
FILE: Makefile
================================================
.PHONY: build test install release
build test install:
$(MAKE) -C godocdown $@
release: build
godocdown/godocdown -template example.template $(HOME)/go/src/pkg/strings > example.markdown
(cd godocdown && ./godocdown -signature > README.markdown) || false
cp godocdown/README.markdown .
================================================
FILE: README.markdown
================================================
# godocdown
--
Command godocdown generates Go documentation in a GitHub-friendly Markdown
format.
$ go get github.com/robertkrimen/godocdown/godocdown
$ godocdown /path/to/package > README.markdown
# Generate documentation for the package/command in the current directory
$ godocdown > README.markdown
# Generate standard Markdown
$ godocdown -plain .
This program is targeted at providing nice-looking documentation for GitHub.
With this in mind, it generates GitHub Flavored Markdown
(http://github.github.com/github-flavored-markdown/) by default. This can be
changed with the use of the "plain" flag to generate standard Markdown.
### Install
go get github.com/robertkrimen/godocdown/godocdown
### Example
http://github.com/robertkrimen/godocdown/blob/master/example.markdown
### Usage
-output=""
Write output to a file instead of stdout
Write to stdout with -
-template=""
The template file to use
-no-template=false
Disable template processing
-plain=false
Emit standard Markdown, rather than Github Flavored Markdown
-heading="TitleCase1Word"
Heading detection method: 1Word, TitleCase, Title, TitleCase1Word, ""
For each line of the package declaration, godocdown attempts to detect if
a heading is present via a pattern match. If a heading is detected,
it prefixes the line with a Markdown heading indicator (typically "###").
1Word: Only a single word on the entire line
[A-Za-z0-9_-]+
TitleCase: A line where each word has the first letter capitalized
([A-Z][A-Za-z0-9_-]\s*)+
Title: A line without punctuation (e.g. a period at the end)
([A-Za-z0-9_-]\s*)+
TitleCase1Word: The line matches either the TitleCase or 1Word pattern
### Templating
In addition to Markdown rendering, godocdown provides templating via
text/template (http://golang.org/pkg/text/template/) for further customization.
By putting a file named ".godocdown.template" (or one from the list below) in
the same directory as your package/command, godocdown will know to use the file
as a template.
# text/template
.godocdown.markdown
.godocdown.md
.godocdown.template
.godocdown.tmpl
A template file can also be specified with the "-template" parameter
Along with the standard template functionality, the starting data argument has
the following interface:
{{ .Emit }}
// Emit the standard documentation (what godocdown would emit without a template)
{{ .EmitHeader }}
// Emit the package name and an import line (if one is present/needed)
{{ .EmitSynopsis }}
// Emit the package declaration
{{ .EmitUsage }}
// Emit package usage, which includes a constants section, a variables section,
// a functions section, and a types section. In addition, each type may have its own constant,
// variable, and/or function/method listing.
{{ if .IsCommand }} ... {{ end }}
// A boolean indicating whether the given package is a command or a plain package
{{ .Name }}
// The name of the package/command (string)
{{ .ImportPath }}
// The import path for the package (string)
// (This field will be the empty string if godocdown is unable to guess it)
--
**godocdown** http://github.com/robertkrimen/godocdown
================================================
FILE: example/.godocdown.markdown
================================================
{{ .Emit }}
{{ .EmitSignature }}
--
This was via template
================================================
FILE: example/example.go
================================================
/*
Package example is an example package with documentation
// Here is some code
func example() {
abc := 1 + 1
}()
Installation
# This is how to install it:
$ curl http://example.com
$ tar xf example.tar.gz -C .
$ ./example &
*/
package example
// A constant section
const Other = 3
// A variable section
var (
This = 1
this = 0
// A description of That
That = 2.1
)
// Another constant section
const (
Another = 0
Again = "this"
)
// Example is a function that does nothing
func Example() {
}
// ExampleType is a type of nothing
//
// // Here is how to use it:
// return &ExampleType{
// First: 1,
// Second: "second",
// nil,
// }
type ExampleType struct {
First int
Second string
Third float64
Parent *ExampleType
first int
hidden string
}
func (ExampleType) Set() bool {
return false
}
func NewExample() *ExampleType {
return &ExampleType{}
}
================================================
FILE: example.markdown
================================================
# Example godocdown (strings)
This markdown was generated with the help of custom template file ([example.template](http://github.com/robertkrimen/godocdown/blob/master/example.template)). To add custom
markdown to your documentation, you can do something like:
godocdown -template=godocdown.tmpl ...
The template format is the standard Go text/template: http://golang.org/pkg/text/template
Along with the standard template functionality, the starting data argument has the following interface:
{{ .Emit }}
// Emit the standard documentation (what godocdown would emit without a template)
{{ .EmitHeader }}
// Emit the package name and an import line (if one is present/needed)
{{ .EmitSynopsis }}
// Emit the package declaration
{{ .EmitUsage }}
// Emit package usage, which includes a constants section, a variables section,
// a functions section, and a types section. In addition, each type may have its own constant,
// variable, and/or function/method listing.
{{ if .IsCommand }} ... {{ end }}
// A boolean indicating whether the given package is a command or a plain package
{{ .Name }}
// The name of the package/command (string)
{{ .ImportPath }}
// The import path for the package (string)
// (This field will be the empty string if godocdown is unable to guess it)
godocdown for the http://golang.org/pkg/strings package:
--
# strings
--
import "strings"
Package strings implements simple functions to manipulate strings.
## Usage
#### func Contains
```go
func Contains(s, substr string) bool
```
Contains returns true if substr is within s.
#### func ContainsAny
```go
func ContainsAny(s, chars string) bool
```
ContainsAny returns true if any Unicode code points in chars are within s.
#### func ContainsRune
```go
func ContainsRune(s string, r rune) bool
```
ContainsRune returns true if the Unicode code point r is within s.
#### func Count
```go
func Count(s, sep string) int
```
Count counts the number of non-overlapping instances of sep in s.
#### func EqualFold
```go
func EqualFold(s, t string) bool
```
EqualFold reports whether s and t, interpreted as UTF-8 strings, are equal under
Unicode case-folding.
#### func Fields
```go
func Fields(s string) []string
```
Fields splits the string s around each instance of one or more consecutive white
space characters, as defined by unicode.IsSpace, returning an array of
substrings of s or an empty list if s contains only white space.
#### func FieldsFunc
```go
func FieldsFunc(s string, f func(rune) bool) []string
```
FieldsFunc splits the string s at each run of Unicode code points c satisfying
f(c) and returns an array of slices of s. If all code points in s satisfy f(c)
or the string is empty, an empty slice is returned.
#### func HasPrefix
```go
func HasPrefix(s, prefix string) bool
```
HasPrefix tests whether the string s begins with prefix.
#### func HasSuffix
```go
func HasSuffix(s, suffix string) bool
```
HasSuffix tests whether the string s ends with suffix.
#### func Index
```go
func Index(s, sep string) int
```
Index returns the index of the first instance of sep in s, or -1 if sep is not
present in s.
#### func IndexAny
```go
func IndexAny(s, chars string) int
```
IndexAny returns the index of the first instance of any Unicode code point from
chars in s, or -1 if no Unicode code point from chars is present in s.
#### func IndexFunc
```go
func IndexFunc(s string, f func(rune) bool) int
```
IndexFunc returns the index into s of the first Unicode code point satisfying
f(c), or -1 if none do.
#### func IndexRune
```go
func IndexRune(s string, r rune) int
```
IndexRune returns the index of the first instance of the Unicode code point r,
or -1 if rune is not present in s.
#### func Join
```go
func Join(a []string, sep string) string
```
Join concatenates the elements of a to create a single string. The separator
string sep is placed between elements in the resulting string.
#### func LastIndex
```go
func LastIndex(s, sep string) int
```
LastIndex returns the index of the last instance of sep in s, or -1 if sep is
not present in s.
#### func LastIndexAny
```go
func LastIndexAny(s, chars string) int
```
LastIndexAny returns the index of the last instance of any Unicode code point
from chars in s, or -1 if no Unicode code point from chars is present in s.
#### func LastIndexFunc
```go
func LastIndexFunc(s string, f func(rune) bool) int
```
LastIndexFunc returns the index into s of the last Unicode code point satisfying
f(c), or -1 if none do.
#### func Map
```go
func Map(mapping func(rune) rune, s string) string
```
Map returns a copy of the string s with all its characters modified according to
the mapping function. If mapping returns a negative value, the character is
dropped from the string with no replacement.
#### func Repeat
```go
func Repeat(s string, count int) string
```
Repeat returns a new string consisting of count copies of the string s.
#### func Replace
```go
func Replace(s, old, new string, n int) string
```
Replace returns a copy of the string s with the first n non-overlapping
instances of old replaced by new. If n < 0, there is no limit on the number of
replacements.
#### func Split
```go
func Split(s, sep string) []string
```
Split slices s into all substrings separated by sep and returns a slice of the
substrings between those separators. If sep is empty, Split splits after each
UTF-8 sequence. It is equivalent to SplitN with a count of -1.
#### func SplitAfter
```go
func SplitAfter(s, sep string) []string
```
SplitAfter slices s into all substrings after each instance of sep and returns a
slice of those substrings. If sep is empty, SplitAfter splits after each UTF-8
sequence. It is equivalent to SplitAfterN with a count of -1.
#### func SplitAfterN
```go
func SplitAfterN(s, sep string, n int) []string
```
SplitAfterN slices s into substrings after each instance of sep and returns a
slice of those substrings. If sep is empty, SplitAfterN splits after each UTF-8
sequence. The count determines the number of substrings to return:
n > 0: at most n substrings; the last substring will be the unsplit remainder.
n == 0: the result is nil (zero substrings)
n < 0: all substrings
#### func SplitN
```go
func SplitN(s, sep string, n int) []string
```
SplitN slices s into substrings separated by sep and returns a slice of the
substrings between those separators. If sep is empty, SplitN splits after each
UTF-8 sequence. The count determines the number of substrings to return:
n > 0: at most n substrings; the last substring will be the unsplit remainder.
n == 0: the result is nil (zero substrings)
n < 0: all substrings
#### func Title
```go
func Title(s string) string
```
Title returns a copy of the string s with all Unicode letters that begin words
mapped to their title case.
BUG: The rule Title uses for word boundaries does not handle Unicode punctuation
properly.
#### func ToLower
```go
func ToLower(s string) string
```
ToLower returns a copy of the string s with all Unicode letters mapped to their
lower case.
#### func ToLowerSpecial
```go
func ToLowerSpecial(_case unicode.SpecialCase, s string) string
```
ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to
their lower case, giving priority to the special casing rules.
#### func ToTitle
```go
func ToTitle(s string) string
```
ToTitle returns a copy of the string s with all Unicode letters mapped to their
title case.
#### func ToTitleSpecial
```go
func ToTitleSpecial(_case unicode.SpecialCase, s string) string
```
ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to
their title case, giving priority to the special casing rules.
#### func ToUpper
```go
func ToUpper(s string) string
```
ToUpper returns a copy of the string s with all Unicode letters mapped to their
upper case.
#### func ToUpperSpecial
```go
func ToUpperSpecial(_case unicode.SpecialCase, s string) string
```
ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to
their upper case, giving priority to the special casing rules.
#### func Trim
```go
func Trim(s string, cutset string) string
```
Trim returns a slice of the string s with all leading and trailing Unicode code
points contained in cutset removed.
#### func TrimFunc
```go
func TrimFunc(s string, f func(rune) bool) string
```
TrimFunc returns a slice of the string s with all leading and trailing Unicode
code points c satisfying f(c) removed.
#### func TrimLeft
```go
func TrimLeft(s string, cutset string) string
```
TrimLeft returns a slice of the string s with all leading Unicode code points
contained in cutset removed.
#### func TrimLeftFunc
```go
func TrimLeftFunc(s string, f func(rune) bool) string
```
TrimLeftFunc returns a slice of the string s with all leading Unicode code
points c satisfying f(c) removed.
#### func TrimPrefix
```go
func TrimPrefix(s, prefix string) string
```
TrimPrefix returns s without the provided leading prefix string. If s doesn't
start with prefix, s is returned unchanged.
#### func TrimRight
```go
func TrimRight(s string, cutset string) string
```
TrimRight returns a slice of the string s, with all trailing Unicode code points
contained in cutset removed.
#### func TrimRightFunc
```go
func TrimRightFunc(s string, f func(rune) bool) string
```
TrimRightFunc returns a slice of the string s with all trailing Unicode code
points c satisfying f(c) removed.
#### func TrimSpace
```go
func TrimSpace(s string) string
```
TrimSpace returns a slice of the string s, with all leading and trailing white
space removed, as defined by Unicode.
#### func TrimSuffix
```go
func TrimSuffix(s, suffix string) string
```
TrimSuffix returns s without the provided trailing suffix string. If s doesn't
end with suffix, s is returned unchanged.
#### type Reader
```go
type Reader struct {
}
```
A Reader implements the io.Reader, io.ReaderAt, io.Seeker, io.WriterTo,
io.ByteScanner, and io.RuneScanner interfaces by reading from a string.
#### func NewReader
```go
func NewReader(s string) *Reader
```
NewReader returns a new Reader reading from s. It is similar to
bytes.NewBufferString but more efficient and read-only.
#### func (*Reader) Len
```go
func (r *Reader) Len() int
```
Len returns the number of bytes of the unread portion of the string.
#### func (*Reader) Read
```go
func (r *Reader) Read(b []byte) (n int, err error)
```
#### func (*Reader) ReadAt
```go
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)
```
#### func (*Reader) ReadByte
```go
func (r *Reader) ReadByte() (b byte, err error)
```
#### func (*Reader) ReadRune
```go
func (r *Reader) ReadRune() (ch rune, size int, err error)
```
#### func (*Reader) Seek
```go
func (r *Reader) Seek(offset int64, whence int) (int64, error)
```
Seek implements the io.Seeker interface.
#### func (*Reader) UnreadByte
```go
func (r *Reader) UnreadByte() error
```
#### func (*Reader) UnreadRune
```go
func (r *Reader) UnreadRune() error
```
#### func (*Reader) WriteTo
```go
func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
```
WriteTo implements the io.WriterTo interface.
#### type Replacer
```go
type Replacer struct {
}
```
A Replacer replaces a list of strings with replacements.
#### func NewReplacer
```go
func NewReplacer(oldnew ...string) *Replacer
```
NewReplacer returns a new Replacer from a list of old, new string pairs.
Replacements are performed in order, without overlapping matches.
#### func (*Replacer) Replace
```go
func (r *Replacer) Replace(s string) string
```
Replace returns a copy of s with all replacements performed.
#### func (*Replacer) WriteString
```go
func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error)
```
WriteString writes s to w with all replacements performed.
================================================
FILE: example.template
================================================
# Example godocdown (strings)
This markdown was generated with the help of custom template file ([example.template](http://github.com/robertkrimen/godocdown/blob/master/example.template)). To add custom
markdown to your documentation, you can do something like:
godocdown -template=godocdown.tmpl ...
The template format is the standard Go text/template: http://golang.org/pkg/text/template
Along with the standard template functionality, the starting data argument has the following interface:
{{ "{{ .Emit }}" }}
// Emit the standard documentation (what godocdown would emit without a template)
{{ "{{ .EmitHeader }}" }}
// Emit the package name and an import line (if one is present/needed)
{{ "{{ .EmitSynopsis }}" }}
// Emit the package declaration
{{ "{{ .EmitUsage }}" }}
// Emit package usage, which includes a constants section, a variables section,
// a functions section, and a types section. In addition, each type may have its own constant,
// variable, and/or function/method listing.
{{ "{{ if .IsCommand }} ... {{ end }}" }}
// A boolean indicating whether the given package is a command or a plain package
{{ "{{ .Name }}" }}
// The name of the package/command (string)
{{ "{{ .ImportPath }}" }}
// The import path for the package (string)
// (This field will be the empty string if godocdown is unable to guess it)
godocdown for the http://golang.org/pkg/strings package:
--
{{ .Emit }}
================================================
FILE: godocdown/.test/godocdown.markdown/.godocdown.markdown
================================================
================================================
FILE: godocdown/.test/godocdown.markdown/.godocdown.md
================================================
================================================
FILE: godocdown/.test/godocdown.markdown/.godocdown.template
================================================
================================================
FILE: godocdown/.test/godocdown.markdown/.godocdown.tmpl
================================================
================================================
FILE: godocdown/.test/godocdown.md/.godocdown.md
================================================
================================================
FILE: godocdown/.test/godocdown.md/.godocdown.template
================================================
================================================
FILE: godocdown/.test/godocdown.md/.godocdown.tmpl
================================================
================================================
FILE: godocdown/.test/godocdown.template/.godocdown.template
================================================
================================================
FILE: godocdown/.test/godocdown.template/.godocdown.tmpl
================================================
================================================
FILE: godocdown/.test/godocdown.tmpl/.godocdown.tmpl
================================================
================================================
FILE: godocdown/.test/issue3/issue3.go
================================================
// Documentation for package issue3
//
// Nothing happens.
//
// Some code happens.
package issue3
// Documentation for func Test()
//
// Something happens.
//
// Some code happens.
func Test() {
}
================================================
FILE: godocdown/7f_shim
================================================
#!/usr/bin/env perl
use strict;
use warnings;
my @input = <STDIN>;
my $longest = 0;
for (@input) {
chomp;
s/\s*\x{7f}\s*$//;
my $length = length $_;
if ($length > $longest) {
$longest = $length;
}
}
$longest += 4;
for (@input) {
chomp;
my $length = length $_;
print $_;
print " " x ($longest - $length);
print "\x{7f}\n";
}
================================================
FILE: godocdown/Makefile
================================================
.PHONY: build test test-example install release
build: test
go build
test:
go test -i
go test
test-example: build
./godocdown -signature example > test/README.markdown
#cd test && git commit -m 'WIP' * && git push
install:
go install
release:
$(MAKE) -C .. $@
================================================
FILE: godocdown/README.markdown
================================================
# godocdown
--
Command godocdown generates Go documentation in a GitHub-friendly Markdown
format.
$ go get github.com/robertkrimen/godocdown/godocdown
$ godocdown /path/to/package > README.markdown
# Generate documentation for the package/command in the current directory
$ godocdown > README.markdown
# Generate standard Markdown
$ godocdown -plain .
This program is targeted at providing nice-looking documentation for GitHub.
With this in mind, it generates GitHub Flavored Markdown
(http://github.github.com/github-flavored-markdown/) by default. This can be
changed with the use of the "plain" flag to generate standard Markdown.
### Install
go get github.com/robertkrimen/godocdown/godocdown
### Example
http://github.com/robertkrimen/godocdown/blob/master/example.markdown
### Usage
-output=""
Write output to a file instead of stdout
Write to stdout with -
-template=""
The template file to use
-no-template=false
Disable template processing
-plain=false
Emit standard Markdown, rather than Github Flavored Markdown
-heading="TitleCase1Word"
Heading detection method: 1Word, TitleCase, Title, TitleCase1Word, ""
For each line of the package declaration, godocdown attempts to detect if
a heading is present via a pattern match. If a heading is detected,
it prefixes the line with a Markdown heading indicator (typically "###").
1Word: Only a single word on the entire line
[A-Za-z0-9_-]+
TitleCase: A line where each word has the first letter capitalized
([A-Z][A-Za-z0-9_-]\s*)+
Title: A line without punctuation (e.g. a period at the end)
([A-Za-z0-9_-]\s*)+
TitleCase1Word: The line matches either the TitleCase or 1Word pattern
### Templating
In addition to Markdown rendering, godocdown provides templating via
text/template (http://golang.org/pkg/text/template/) for further customization.
By putting a file named ".godocdown.template" (or one from the list below) in
the same directory as your package/command, godocdown will know to use the file
as a template.
# text/template
.godocdown.markdown
.godocdown.md
.godocdown.template
.godocdown.tmpl
A template file can also be specified with the "-template" parameter
Along with the standard template functionality, the starting data argument has
the following interface:
{{ .Emit }}
// Emit the standard documentation (what godocdown would emit without a template)
{{ .EmitHeader }}
// Emit the package name and an import line (if one is present/needed)
{{ .EmitSynopsis }}
// Emit the package declaration
{{ .EmitUsage }}
// Emit package usage, which includes a constants section, a variables section,
// a functions section, and a types section. In addition, each type may have its own constant,
// variable, and/or function/method listing.
{{ if .IsCommand }} ... {{ end }}
// A boolean indicating whether the given package is a command or a plain package
{{ .Name }}
// The name of the package/command (string)
{{ .ImportPath }}
// The import path for the package (string)
// (This field will be the empty string if godocdown is unable to guess it)
--
**godocdown** http://github.com/robertkrimen/godocdown
================================================
FILE: godocdown/dbg/dbg.go
================================================
// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) from github.com/robertkrimen/dbg
/*
Package dbg is a println/printf/log-debugging utility library.
import (
Dbg "github.com/robertkrimen/dbg"
)
dbg, dbgf := Dbg.New()
dbg("Emit some debug stuff", []byte{120, 121, 122, 122, 121}, math.Pi)
# "2013/01/28 16:50:03 Emit some debug stuff [120 121 122 122 121] 3.141592653589793"
dbgf("With a %s formatting %.2f", "little", math.Pi)
# "2013/01/28 16:51:55 With a little formatting (3.14)"
dbgf("%/fatal//A fatal debug statement: should not be here")
# "A fatal debug statement: should not be here"
# ...and then, os.Exit(1)
dbgf("%/panic//Can also panic %s", "this")
# "Can also panic this"
# ...as a panic, equivalent to: panic("Can also panic this")
dbgf("Any %s arguments without a corresponding %%", "extra", "are treated like arguments to dbg()")
# "2013/01/28 17:14:40 Any extra arguments (without a corresponding %) are treated like arguments to dbg()"
dbgf("%d %d", 1, 2, 3, 4, 5)
# "2013/01/28 17:16:32 Another example: 1 2 3 4 5"
dbgf("%@: Include the function name for a little context (via %s)", "%@")
# "2013... github.com/robertkrimen/dbg.TestSynopsis: Include the function name for a little context (via %@)"
By default, dbg uses log (log.Println, log.Printf, log.Panic, etc.) for output.
However, you can also provide your own output destination by invoking dbg.New with
a customization function:
import (
"bytes"
Dbg "github.com/robertkrimen/dbg"
"os"
)
# dbg to os.Stderr
dbg, dbgf := Dbg.New(func(dbgr *Dbgr) {
dbgr.SetOutput(os.Stderr)
})
# A slightly contrived example:
var buffer bytes.Buffer
dbg, dbgf := New(func(dbgr *Dbgr) {
dbgr.SetOutput(&buffer)
})
*/
package dbg
import (
"bytes"
"fmt"
"io"
"log"
"os"
"regexp"
"runtime"
"strings"
"unicode"
)
type _frmt struct {
ctl string
format string
operandCount int
panic bool
fatal bool
check bool
}
var (
ctlTest = regexp.MustCompile(`^\s*%/`)
ctlScan = regexp.MustCompile(`%?/(panic|fatal|check)(?:\s|$)`)
)
func operandCount(format string) int {
count := 0
end := len(format)
for at := 0; at < end; {
for at < end && format[at] != '%' {
at++
}
at++
if at < end {
if format[at] != '%' && format[at] != '@' {
count++
}
at++
}
}
return count
}
func parseFormat(format string) (frmt _frmt) {
if ctlTest.MatchString(format) {
format = strings.TrimLeftFunc(format, unicode.IsSpace)
index := strings.Index(format, "//")
if index != -1 {
frmt.ctl = format[0:index]
format = format[index+2:] // Skip the second slash via +2 (instead of +1)
} else {
frmt.ctl = format
format = ""
}
for _, tmp := range ctlScan.FindAllStringSubmatch(frmt.ctl, -1) {
for _, value := range tmp[1:] {
switch value {
case "panic":
frmt.panic = true
case "fatal":
frmt.fatal = true
case "check":
frmt.check = true
}
}
}
}
frmt.format = format
frmt.operandCount = operandCount(format)
return
}
type Dbgr struct {
emit _emit
}
type DbgFunction func(values ...interface{})
func NewDbgr() *Dbgr {
self := &Dbgr{}
return self
}
/*
New will create and return a pair of debugging functions. You can customize where
they output to by passing in an (optional) customization function:
import (
Dbg "github.com/robertkrimen/dbg"
"os"
)
# dbg to os.Stderr
dbg, dbgf := Dbg.New(func(dbgr *Dbgr) {
dbgr.SetOutput(os.Stderr)
})
*/
func New(options ...interface{}) (dbg DbgFunction, dbgf DbgFunction) {
dbgr := NewDbgr()
if len(options) > 0 {
if fn, ok := options[0].(func(*Dbgr)); ok {
fn(dbgr)
}
}
return dbgr.DbgDbgf()
}
func (self Dbgr) Dbg(values ...interface{}) {
self.getEmit().emit(_frmt{}, "", values...)
}
func (self Dbgr) Dbgf(values ...interface{}) {
self.dbgf(values...)
}
func (self Dbgr) DbgDbgf() (dbg DbgFunction, dbgf DbgFunction) {
dbg = func(vl ...interface{}) {
self.Dbg(vl...)
}
dbgf = func(vl ...interface{}) {
self.dbgf(vl...)
}
return dbg, dbgf // Redundant, but...
}
func (self Dbgr) dbgf(values ...interface{}) {
var frmt _frmt
if len(values) > 0 {
tmp := fmt.Sprint(values[0])
frmt = parseFormat(tmp)
values = values[1:]
}
buffer_f := bytes.Buffer{}
format := frmt.format
end := len(format)
for at := 0; at < end; {
last := at
for at < end && format[at] != '%' {
at++
}
if at > last {
buffer_f.WriteString(format[last:at])
}
if at >= end {
break
}
// format[at] == '%'
at++
// format[at] == ?
if format[at] == '@' {
depth := 2
pc, _, _, _ := runtime.Caller(depth)
name := runtime.FuncForPC(pc).Name()
buffer_f.WriteString(name)
} else {
buffer_f.WriteString(format[at-1 : at+1])
}
at++
}
//values_f := append([]interface{}{}, values[0:frmt.operandCount]...)
values_f := values[0:frmt.operandCount]
values_dbg := values[frmt.operandCount:]
if len(values_dbg) > 0 {
// Adjust frmt.format:
// (%v instead of %s because: frmt.check)
{
tmp := format
if len(tmp) > 0 {
if unicode.IsSpace(rune(tmp[len(tmp)-1])) {
buffer_f.WriteString("%v")
} else {
buffer_f.WriteString(" %v")
}
} else if frmt.check {
// Performing a check, so no output
} else {
buffer_f.WriteString("%v")
}
}
// Adjust values_f:
if !frmt.check {
tmp := []string{}
for _, value := range values_dbg {
tmp = append(tmp, fmt.Sprintf("%v", value))
}
// First, make a copy of values_f, so we avoid overwriting values_dbg when appending
values_f = append([]interface{}{}, values_f...)
values_f = append(values_f, strings.Join(tmp, " "))
}
}
format = buffer_f.String()
if frmt.check {
// We do not actually emit to the log, but panic if
// a non-nil value is detected (e.g. a non-nil error)
for _, value := range values_dbg {
if value != nil {
if format == "" {
panic(value)
} else {
panic(fmt.Sprintf(format, append(values_f, value)...))
}
}
}
} else {
self.getEmit().emit(frmt, format, values_f...)
}
}
// Idiot-proof &Dbgr{}, etc.
func (self *Dbgr) getEmit() _emit {
if self.emit == nil {
self.emit = standardEmit()
}
return self.emit
}
// SetOutput will accept the following as a destination for output:
//
// *log.Logger Print*/Panic*/Fatal* of the logger
// io.Writer -
// nil Reset to the default output (os.Stderr)
// "log" Print*/Panic*/Fatal* via the "log" package
//
func (self *Dbgr) SetOutput(output interface{}) {
if output == nil {
self.emit = standardEmit()
return
}
switch output := output.(type) {
case *log.Logger:
self.emit = _emitLogger{
logger: output,
}
return
case io.Writer:
self.emit = _emitWriter{
writer: output,
}
return
case string:
if output == "log" {
self.emit = _emitLog{}
return
}
}
panic(output)
}
// ======== //
// = emit = //
// ======== //
func standardEmit() _emit {
return _emitWriter{
writer: os.Stderr,
}
}
func ln(tmp string) string {
length := len(tmp)
if length > 0 && tmp[length-1] != '\n' {
return tmp + "\n"
}
return tmp
}
type _emit interface {
emit(_frmt, string, ...interface{})
}
type _emitWriter struct {
writer io.Writer
}
func (self _emitWriter) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
fmt.Fprintln(self.writer, values...)
} else {
if frmt.panic {
panic(fmt.Sprintf(format, values...))
}
fmt.Fprintf(self.writer, ln(format), values...)
if frmt.fatal {
os.Exit(1)
}
}
}
type _emitLogger struct {
logger *log.Logger
}
func (self _emitLogger) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
self.logger.Println(values...)
} else {
if frmt.panic {
self.logger.Panicf(format, values...)
} else if frmt.fatal {
self.logger.Fatalf(format, values...)
} else {
self.logger.Printf(format, values...)
}
}
}
type _emitLog struct {
}
func (self _emitLog) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
log.Println(values...)
} else {
if frmt.panic {
log.Panicf(format, values...)
} else if frmt.fatal {
log.Fatalf(format, values...)
} else {
log.Printf(format, values...)
}
}
}
================================================
FILE: godocdown/dbg.go
================================================
// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg
package main
import (
Dbg "github.com/robertkrimen/godocdown/godocdown/dbg"
)
var dbg, dbgf = Dbg.New()
================================================
FILE: godocdown/go_doc_totext.go
================================================
package main
// Our own, slightly different version of ToText.
import (
"io"
"regexp"
"strings"
"unicode"
"unicode/utf8"
)
var (
ldquo = []byte("“")
rdquo = []byte("”")
)
const (
// Regexp for Go identifiers
identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
// Regexp for URLs
protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
hostPart = `[a-zA-Z0-9_@\-]+`
filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
urlRx = protocol + `//` + // http://
hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
filePart + `([:.,]` + filePart + `)*`
)
var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
func indentLen(s string) int {
i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
i++
}
return i
}
func isBlank(s string) bool {
return len(s) == 0 || (len(s) == 1 && s[0] == '\n')
}
func commonPrefix(a, b string) string {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] {
i++
}
return a[0:i]
}
func unindent(block []string) {
if len(block) == 0 {
return
}
// compute maximum common white prefix
prefix := block[0][0:indentLen(block[0])]
for _, line := range block {
if !isBlank(line) {
prefix = commonPrefix(prefix, line[0:indentLen(line)])
}
}
n := len(prefix)
// remove
for i, line := range block {
if !isBlank(line) {
block[i] = line[n:]
}
}
}
// heading returns the trimmed line if it passes as a section heading;
// otherwise it returns the empty string.
func heading(line string) string {
line = strings.TrimSpace(line)
if len(line) == 0 {
return ""
}
// a heading must start with an uppercase letter
r, _ := utf8.DecodeRuneInString(line)
if !unicode.IsLetter(r) || !unicode.IsUpper(r) {
return ""
}
// it must end in a letter or digit:
r, _ = utf8.DecodeLastRuneInString(line)
if !unicode.IsLetter(r) && !unicode.IsDigit(r) {
return ""
}
// exclude lines with illegal characters
if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
return ""
}
// allow "'" for possessive "'s" only
for b := line; ; {
i := strings.IndexRune(b, '\'')
if i < 0 {
break
}
if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') {
return "" // not followed by "s "
}
b = b[i+2:]
}
return line
}
type op int
const (
opPara op = iota
opHead
opPre
)
type block struct {
op op
lines []string
}
var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`)
func anchorID(line string) string {
// Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols.
return "hdr-" + nonAlphaNumRx.ReplaceAllString(line, "_")
}
func blocks(text string) []block {
var (
out []block
para []string
lastWasBlank = false
lastWasHeading = false
)
close := func() {
if para != nil {
out = append(out, block{opPara, para})
para = nil
}
}
lines := strings.SplitAfter(text, "\n")
unindent(lines)
for i := 0; i < len(lines); {
line := lines[i]
if isBlank(line) {
// close paragraph
close()
i++
lastWasBlank = true
continue
}
if indentLen(line) > 0 {
// close paragraph
close()
// count indented or blank lines
j := i + 1
for j < len(lines) && (isBlank(lines[j]) || indentLen(lines[j]) > 0) {
j++
}
// but not trailing blank lines
for j > i && isBlank(lines[j-1]) {
j--
}
pre := lines[i:j]
i = j
unindent(pre)
// put those lines in a pre block
out = append(out, block{opPre, pre})
lastWasHeading = false
continue
}
if lastWasBlank && !lastWasHeading && i+2 < len(lines) &&
isBlank(lines[i+1]) && !isBlank(lines[i+2]) && indentLen(lines[i+2]) == 0 {
// current line is non-blank, surrounded by blank lines
// and the next non-blank line is not indented: this
// might be a heading.
if head := heading(line); head != "" {
close()
out = append(out, block{opHead, []string{head}})
i += 2
lastWasHeading = true
continue
}
}
// open paragraph
lastWasBlank = false
lastWasHeading = false
para = append(para, lines[i])
i++
}
close()
return out
}
// ToText prepares comment text for presentation in textual output.
// It wraps paragraphs of text to width or fewer Unicode code points
// and then prefixes each line with the indent. In preformatted sections
// (such as program text), it prefixes each non-blank line with preIndent.
func toText(w io.Writer, text string, indent, preIndent string, width int) {
l := lineWrapper{
out: w,
width: width,
indent: indent,
}
for _, b := range blocks(text) {
switch b.op {
case opPara:
// l.write will add leading newline if required
for _, line := range b.lines {
l.write(line)
}
l.flush()
case opHead:
w.Write(nl)
for _, line := range b.lines {
l.write(line + "\n")
}
l.flush()
case opPre:
w.Write(nl)
for _, line := range b.lines {
if !isBlank(line) {
w.Write([]byte(preIndent))
w.Write([]byte(line))
} else {
w.Write([]byte(line))
}
}
}
}
}
type lineWrapper struct {
out io.Writer
printed bool
width int
indent string
n int
pendSpace int
}
var nl = []byte("\n")
var space = []byte(" ")
func (l *lineWrapper) write(text string) {
if l.n == 0 && l.printed {
l.out.Write(nl) // blank line before new paragraph
}
l.printed = true
for _, f := range strings.Fields(text) {
w := utf8.RuneCountInString(f)
// wrap if line is too long
if l.n > 0 && l.n+l.pendSpace+w > l.width {
l.out.Write(nl)
l.n = 0
l.pendSpace = 0
}
if l.n == 0 {
l.out.Write([]byte(l.indent))
}
l.out.Write(space[:l.pendSpace])
l.out.Write([]byte(f))
l.n += l.pendSpace + w
l.pendSpace = 1
}
}
func (l *lineWrapper) flush() {
if l.n == 0 {
return
}
l.out.Write(nl)
l.pendSpace = 0
l.n = 0
}
================================================
FILE: godocdown/kilt/at.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"os"
)
// At
func (self Kilt) At(there string, fn func() error) []error {
return At(there, fn)
}
func At(there string, fn func() error) (err []error) {
origin, err_ := os.Getwd()
if err_ != nil {
origin = ""
return []error{err_, nil}
}
err_ = os.Chdir(there)
if err_ != nil {
origin = ""
return []error{err_, nil}
}
defer func() {
if origin != "" {
err_ = os.Chdir(origin)
if err != nil {
err[0] = err_
} else {
err = []error{err_, nil}
}
}
}()
err_ = fn()
if err_ != nil {
return []error{nil, err_}
}
return nil
}
================================================
FILE: godocdown/kilt/exec_command.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"os/exec"
)
// ExecCommand
func commandArguments(values ...string) []string {
arguments := make([]string, 0, len(values))
for _, value := range values {
if value == "\x00" {
continue
}
arguments = append(arguments, value)
}
return arguments
}
func (self Kilt) ExecCommand(program string, arguments ...string) *exec.Cmd {
return ExecCommand(program, arguments...)
}
func ExecCommand(program string, arguments ...string) *exec.Cmd {
return exec.Command(program, commandArguments(arguments...)...)
}
================================================
FILE: godocdown/kilt/grave_trim.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"unicode"
)
func (self Kilt) GraveTrim(target string) string {
return GraveTrim(target)
}
// GraveTrim
func GraveTrim(target string) string {
// Discard \r? Go already does this for raw string literals.
end := len(target)
last := 0
index := 0
for index = 0; index < end; index++ {
chr := rune(target[index])
if chr == '\n' || !unicode.IsSpace(chr) {
last = index
break
}
}
if index >= end {
return ""
}
start := last
if rune(target[start]) == '\n' {
// Skip the leading newline
start++
}
last = end - 1
for index = last; index > start; index-- {
chr := rune(target[index])
if chr == '\n' || !unicode.IsSpace(chr) {
last = index
break
}
}
stop := last
result := target[start : stop+1]
return result
}
================================================
FILE: godocdown/kilt/kilt.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
type Kilt struct {
}
func New() *Kilt {
return &Kilt{}
}
================================================
FILE: godocdown/kilt/print_defaults.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"bufio"
"bytes"
Flag "flag"
"fmt"
"os"
"strings"
)
// PrintDefaults
func (self Kilt) PrintDefaults(flag *Flag.FlagSet) {
PrintDefaults(flag)
}
func PrintDefaults(flag *Flag.FlagSet) {
var into bytes.Buffer
flag.SetOutput(&into)
flag.PrintDefaults()
outfrom := bufio.NewReader(&into)
for {
line, err := outfrom.ReadString('\n')
if err != nil {
break
}
if strings.HasSuffix(line, ": \x00\n") {
continue
}
fmt.Fprint(os.Stderr, line)
}
}
================================================
FILE: godocdown/kilt/sha1.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"crypto/sha1"
"encoding/hex"
"io"
"os"
"path/filepath"
)
// Sha1Path
func (self Kilt) Sha1Path(path ...string) string {
return Sha1Path(path...)
}
func Sha1Path(path ...string) string {
file, err := os.Open(filepath.Join(path...))
if err != nil {
return ""
}
return Sha1Of(file)
}
// Sha1Of
func (self Kilt) Sha1Of(src io.Reader) string {
return Sha1Of(src)
}
func Sha1Of(src io.Reader) string {
hash := sha1.New()
_, err := io.Copy(hash, src)
if err != nil {
return ""
}
return hex.EncodeToString(hash.Sum(nil))
}
// Sha1
func (self Kilt) Sha1(data []byte) string {
return Sha1(data)
}
func Sha1(data []byte) string {
hash := sha1.New()
hash.Write(data)
return hex.EncodeToString(hash.Sum(nil))
}
================================================
FILE: godocdown/kilt/symlink.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"os"
)
// Symlink
func (self Kilt) Symlink(oldname, newname string, overwrite bool) error {
return Symlink(oldname, newname, overwrite)
}
func Symlink(oldname, newname string, overwrite bool) error {
err := os.Symlink(oldname, newname)
if err == nil {
return nil // Success
}
if !os.IsExist(err) {
return err // Failure
}
// Failure, file exists
symbolic := false
{
stat, err := os.Lstat(newname)
if err != nil {
return err
}
symbolic = stat.Mode()&os.ModeSymlink != 0
}
if !symbolic {
return err
}
if !overwrite {
return nil
}
err = os.Remove(newname)
if err != nil {
return err
}
return os.Symlink(oldname, newname)
}
================================================
FILE: godocdown/kilt/write_atomic_file.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt
package kilt
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
)
// WriteAtomicFile
func (self Kilt) WriteAtomicFile(filename string, data io.Reader, mode os.FileMode) error {
return WriteAtomicFile(filename, data, mode)
}
func WriteAtomicFile(filename string, data io.Reader, mode os.FileMode) error {
parent := filepath.Dir(filename)
tmp, err := ioutil.TempDir(parent, ".tmp.")
if err != nil {
return err
}
if len(parent) >= len(tmp) { // Should never, ever happen
return (fmt.Errorf("%s < %s", tmp, parent))
}
defer os.RemoveAll(tmp)
tmpname := filepath.Join(tmp, filepath.Base(filename))
file, err := os.OpenFile(tmpname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, data)
if err != nil {
return err
}
return os.Rename(tmpname, filename)
}
================================================
FILE: godocdown/kilt.go
================================================
// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) for github.com/robertkrimen/kilt
package main
import (
Kilt "github.com/robertkrimen/godocdown/godocdown/kilt"
)
var kilt = Kilt.New()
================================================
FILE: godocdown/main.go
================================================
/*
Command godocdown generates Go documentation in a GitHub-friendly Markdown format.
$ go get github.com/robertkrimen/godocdown/godocdown
$ godocdown /path/to/package > README.markdown
# Generate documentation for the package/command in the current directory
$ godocdown > README.markdown
# Generate standard Markdown
$ godocdown -plain .
This program is targeted at providing nice-looking documentation for GitHub. With this in
mind, it generates GitHub Flavored Markdown (http://github.github.com/github-flavored-markdown/) by
default. This can be changed with the use of the "plain" flag to generate standard Markdown.
Install
go get github.com/robertkrimen/godocdown/godocdown
Example
http://github.com/robertkrimen/godocdown/blob/master/example.markdown
Usage
-output=""
Write output to a file instead of stdout
Write to stdout with -
-template=""
The template file to use
-no-template=false
Disable template processing
-plain=false
Emit standard Markdown, rather than Github Flavored Markdown
-heading="TitleCase1Word"
Heading detection method: 1Word, TitleCase, Title, TitleCase1Word, ""
For each line of the package declaration, godocdown attempts to detect if
a heading is present via a pattern match. If a heading is detected,
it prefixes the line with a Markdown heading indicator (typically "###").
1Word: Only a single word on the entire line
[A-Za-z0-9_-]+
TitleCase: A line where each word has the first letter capitalized
([A-Z][A-Za-z0-9_-]\s*)+
Title: A line without punctuation (e.g. a period at the end)
([A-Za-z0-9_-]\s*)+
TitleCase1Word: The line matches either the TitleCase or 1Word pattern
Templating
In addition to Markdown rendering, godocdown provides templating via text/template (http://golang.org/pkg/text/template/)
for further customization. By putting a file named ".godocdown.template" (or one from the list below) in the same directory as your
package/command, godocdown will know to use the file as a template.
# text/template
.godocdown.markdown
.godocdown.md
.godocdown.template
.godocdown.tmpl
A template file can also be specified with the "-template" parameter
Along with the standard template functionality, the starting data argument has the following interface:
{{ .Emit }}
// Emit the standard documentation (what godocdown would emit without a template)
{{ .EmitHeader }}
// Emit the package name and an import line (if one is present/needed)
{{ .EmitSynopsis }}
// Emit the package declaration
{{ .EmitUsage }}
// Emit package usage, which includes a constants section, a variables section,
// a functions section, and a types section. In addition, each type may have its own constant,
// variable, and/or function/method listing.
{{ if .IsCommand }} ... {{ end }}
// A boolean indicating whether the given package is a command or a plain package
{{ .Name }}
// The name of the package/command (string)
{{ .ImportPath }}
// The import path for the package (string)
// (This field will be the empty string if godocdown is unable to guess it)
*/
package main
import (
"bytes"
Flag "flag"
"fmt"
"go/build"
"go/doc"
"go/parser"
"go/printer"
"go/token"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
Template "text/template"
Time "time"
)
const (
punchCardWidth = 80
debug = false
)
var (
flag = Flag.NewFlagSet("", Flag.ExitOnError)
flag_signature = flag.Bool("signature", false, string(0))
flag_plain = flag.Bool("plain", false, "Emit standard Markdown, rather than Github Flavored Markdown (the default)")
flag_heading = flag.String("heading", "TitleCase1Word", "Heading detection method: 1Word, TitleCase, Title, TitleCase1Word, \"\"")
flag_template = flag.String("template", "", "The template file to use")
flag_noTemplate = flag.Bool("no-template", false, "Disable template processing")
flag_output = ""
_ = func() byte {
flag.StringVar(&flag_output, "output", flag_output, "Write output to a file instead of stdout. Write to stdout with -")
flag.StringVar(&flag_output, "o", flag_output, string(0))
return 0
}()
)
var (
fset *token.FileSet
synopsisHeading1Word_Regexp = regexp.MustCompile("(?m)^([A-Za-z0-9_-]+)$")
synopsisHeadingTitleCase_Regexp = regexp.MustCompile("(?m)^((?:[A-Z][A-Za-z0-9_-]*)(?:[ \t]+[A-Z][A-Za-z0-9_-]*)*)$")
synopsisHeadingTitle_Regexp = regexp.MustCompile("(?m)^((?:[A-Za-z0-9_-]+)(?:[ \t]+[A-Za-z0-9_-]+)*)$")
synopsisHeadingTitleCase1Word_Regexp = regexp.MustCompile("(?m)^((?:[A-Za-z0-9_-]+)|(?:(?:[A-Z][A-Za-z0-9_-]*)(?:[ \t]+[A-Z][A-Za-z0-9_-]*)*))$")
strip_Regexp = regexp.MustCompile("(?m)^\\s*// contains filtered or unexported fields\\s*\n")
indent_Regexp = regexp.MustCompile("(?m)^([^\\n])") // Match at least one character at the start of the line
synopsisHeading_Regexp = synopsisHeading1Word_Regexp
match_7f = regexp.MustCompile(`(?m)[\t ]*\x7f[\t ]*$`)
)
var DefaultStyle = Style{
IncludeImport: true,
SynopsisHeader: "###",
SynopsisHeading: synopsisHeadingTitleCase1Word_Regexp,
UsageHeader: "## Usage\n",
ConstantHeader: "####",
VariableHeader: "####",
FunctionHeader: "####",
TypeHeader: "####",
TypeFunctionHeader: "####",
IncludeSignature: false,
}
var RenderStyle = DefaultStyle
func usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
kilt.PrintDefaults(flag)
executable, err := os.Stat(os.Args[0])
if err != nil {
return
}
time := executable.ModTime()
since := Time.Since(time)
fmt.Fprintf(os.Stderr, "---\n%s (%.2f)\n", time.Format("2006-01-02 15:04 MST"), since.Minutes())
}
func init() {
flag.Usage = usage
}
type Style struct {
IncludeImport bool
SynopsisHeader string
SynopsisHeading *regexp.Regexp
UsageHeader string
ConstantHeader string
VariableHeader string
FunctionHeader string
TypeHeader string
TypeFunctionHeader string
IncludeSignature bool
}
type _document struct {
Name string
pkg *doc.Package
buildPkg *build.Package
IsCommand bool
ImportPath string
}
func takeOut7f(input string) string {
return match_7f.ReplaceAllString(input, "")
}
func _formatIndent(target, indent, preIndent string) string {
var buffer bytes.Buffer
toText(&buffer, target, indent, preIndent, punchCardWidth-2*len(indent))
return buffer.String()
}
func spacer(width int) string {
return strings.Repeat(" ", width)
}
func formatIndent(target string) string {
return _formatIndent(target, spacer(0), spacer(4))
}
func indentCode(target string) string {
if *flag_plain {
return indent(target+"\n", spacer(4))
}
return fmt.Sprintf("```go\n%s\n```", target)
}
func headifySynopsis(target string) string {
detect := RenderStyle.SynopsisHeading
if detect == nil {
return target
}
return detect.ReplaceAllStringFunc(target, func(heading string) string {
return fmt.Sprintf("%s %s", RenderStyle.SynopsisHeader, heading)
})
}
func headlineSynopsis(synopsis, header string, scanner *regexp.Regexp) string {
return scanner.ReplaceAllStringFunc(synopsis, func(headline string) string {
return fmt.Sprintf("%s %s", header, headline)
})
}
func sourceOfNode(target interface{}) string {
var buffer bytes.Buffer
mode := printer.TabIndent | printer.UseSpaces
err := (&printer.Config{Mode: mode, Tabwidth: 4}).Fprint(&buffer, fset, target)
if err != nil {
return ""
}
return strip_Regexp.ReplaceAllString(buffer.String(), "")
}
func indent(target string, indent string) string {
return indent_Regexp.ReplaceAllString(target, indent+"$1")
}
func filterText(input string) string {
// Why is this here?
// Normally, godoc will ALWAYS collapse adjacent lines separated only by whitespace.
// However, if you place a (normally invisible) \x7f character in the documentation,
// this collapse will not happen. Thankfully, Markdown does not need this sort of hack,
// so we remove it.
return takeOut7f(input)
}
func trimSpace(buffer *bytes.Buffer) {
tmp := bytes.TrimSpace(buffer.Bytes())
buffer.Reset()
buffer.Write(tmp)
}
func fromSlash(path string) string {
return filepath.FromSlash(path)
}
/*
This is how godoc does it:
// Determine paths.
//
// If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc,
// we need to map that path somewhere in the fs name space so that routines
// like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target"
// for this. That is, if we get passed a directory like the above, we map that
// directory so that getPageInfo sees it as /target.
const target = "/target"
const cmdPrefix = "cmd/"
path := flag.Arg(0)
var forceCmd bool
var abspath, relpath string
if filepath.IsAbs(path) {
fs.Bind(target, OS(path), "/", bindReplace)
abspath = target
} else if build.IsLocalImport(path) {
cwd, _ := os.Getwd() // ignore errors
path = filepath.Join(cwd, path)
fs.Bind(target, OS(path), "/", bindReplace)
abspath = target
} else if strings.HasPrefix(path, cmdPrefix) {
path = path[len(cmdPrefix):]
forceCmd = true
} else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
fs.Bind(target, OS(bp.Dir), "/", bindReplace)
abspath = target
relpath = bp.ImportPath
} else {
abspath = pathpkg.Join(pkgHandler.fsRoot, path)
}
if relpath == "" {
relpath = abspath
}
*/
func buildImport(target string) (*build.Package, error) {
if filepath.IsAbs(target) {
return build.Default.ImportDir(target, build.FindOnly)
} else if build.IsLocalImport(target) {
base, _ := os.Getwd()
path := filepath.Join(base, target)
return build.Default.ImportDir(path, build.FindOnly)
} else if pkg, _ := build.Default.Import(target, "", build.FindOnly); pkg.Dir != "" && pkg.ImportPath != "" {
return pkg, nil
}
path, _ := filepath.Abs(target) // Even if there is an error, still try?
return build.Default.ImportDir(path, build.FindOnly)
}
func guessImportPath(target string) (string, error) {
buildPkg, err := buildImport(target)
if err != nil {
return "", err
}
if buildPkg.SrcRoot == "" {
return "", nil
}
return buildPkg.ImportPath, nil
}
func loadDocument(target string) (*_document, error) {
buildPkg, err := buildImport(target)
if err != nil {
return nil, err
}
if buildPkg.Dir == "" {
return nil, fmt.Errorf("Could not find package \"%s\"", target)
}
path := buildPkg.Dir
fset = token.NewFileSet()
pkgSet, err := parser.ParseDir(fset, path, func(file os.FileInfo) bool {
name := file.Name()
if name[0] != '.' && strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") {
return true
}
return false
}, parser.ParseComments)
if err != nil {
return nil, fmt.Errorf("Could not parse \"%s\": %v", path, err)
}
importPath := ""
if read, err := ioutil.ReadFile(filepath.Join(path, ".godocdown.import")); err == nil {
importPath = strings.TrimSpace(strings.Split(string(read), "\n")[0])
} else {
importPath = buildPkg.ImportPath
}
{
isCommand := false
name := ""
var pkg *doc.Package
// Choose the best package for documentation. Either
// documentation, main, or whatever the package is.
for _, parsePkg := range pkgSet {
tmpPkg := doc.New(parsePkg, ".", 0)
switch tmpPkg.Name {
case "main":
if isCommand || name != "" {
// We've already seen "package documentation"
// (or something else), so favor that over main.
continue
}
fallthrough
case "documentation":
// We're a command, this package/file contains the documentation
// path is used to get the containing directory in the case of
// command documentation
path, err := filepath.Abs(path)
if err != nil {
panic(err)
}
_, name = filepath.Split(path)
isCommand = true
pkg = tmpPkg
default:
// Just a regular package
name = tmpPkg.Name
pkg = tmpPkg
}
}
if pkg != nil {
return &_document{
Name: name,
pkg: pkg,
buildPkg: buildPkg,
IsCommand: isCommand,
ImportPath: importPath,
}, nil
}
}
return nil, nil
}
func emitString(fn func(*bytes.Buffer)) string {
var buffer bytes.Buffer
fn(&buffer)
trimSpace(&buffer)
return buffer.String()
}
// Emit
func (self *_document) Emit() string {
return emitString(func(buffer *bytes.Buffer) {
self.EmitTo(buffer)
})
}
func (self *_document) EmitTo(buffer *bytes.Buffer) {
// Header
self.EmitHeaderTo(buffer)
// Synopsis
self.EmitSynopsisTo(buffer)
// Usage
if !self.IsCommand {
self.EmitUsageTo(buffer)
}
trimSpace(buffer)
}
// Signature
func (self *_document) EmitSignature() string {
return emitString(func(buffer *bytes.Buffer) {
self.EmitSignatureTo(buffer)
})
}
func (self *_document) EmitSignatureTo(buffer *bytes.Buffer) {
renderSignatureTo(buffer)
trimSpace(buffer)
}
// Header
func (self *_document) EmitHeader() string {
return emitString(func(buffer *bytes.Buffer) {
self.EmitHeaderTo(buffer)
})
}
func (self *_document) EmitHeaderTo(buffer *bytes.Buffer) {
renderHeaderTo(buffer, self)
}
// Synopsis
func (self *_document) EmitSynopsis() string {
return emitString(func(buffer *bytes.Buffer) {
self.EmitSynopsisTo(buffer)
})
}
func (self *_document) EmitSynopsisTo(buffer *bytes.Buffer) {
renderSynopsisTo(buffer, self)
}
// Usage
func (self *_document) EmitUsage() string {
return emitString(func(buffer *bytes.Buffer) {
self.EmitUsageTo(buffer)
})
}
func (self *_document) EmitUsageTo(buffer *bytes.Buffer) {
renderUsageTo(buffer, self)
}
var templateNameList = strings.Fields(`
.godocdown.markdown
.godocdown.md
.godocdown.template
.godocdown.tmpl
`)
func findTemplate(path string) string {
for _, templateName := range templateNameList {
templatePath := filepath.Join(path, templateName)
_, err := os.Stat(templatePath)
if err != nil {
if os.IsExist(err) {
continue
}
continue // Other error reporting?
}
return templatePath
}
return "" // Nothing found
}
func loadTemplate(document *_document) *Template.Template {
if *flag_noTemplate {
return nil
}
templatePath := *flag_template
if templatePath == "" {
templatePath = findTemplate(document.buildPkg.Dir)
}
if templatePath == "" {
return nil
}
template := Template.New("").Funcs(Template.FuncMap{})
template, err := template.ParseFiles(templatePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing template \"%s\": %v", templatePath, err)
os.Exit(1)
}
return template
}
func main() {
flag.Parse(os.Args[1:])
target := flag.Arg(0)
fallbackUsage := false
if target == "" {
fallbackUsage = true
target = "."
}
RenderStyle.IncludeSignature = *flag_signature
switch *flag_heading {
case "1Word":
RenderStyle.SynopsisHeading = synopsisHeading1Word_Regexp
case "TitleCase":
RenderStyle.SynopsisHeading = synopsisHeadingTitleCase_Regexp
case "Title":
RenderStyle.SynopsisHeading = synopsisHeadingTitle_Regexp
case "TitleCase1Word":
RenderStyle.SynopsisHeading = synopsisHeadingTitleCase1Word_Regexp
case "", "-":
RenderStyle.SynopsisHeading = nil
}
document, err := loadDocument(target)
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
}
if document == nil {
// Nothing found.
if fallbackUsage {
usage()
os.Exit(2)
} else {
fmt.Fprintf(os.Stderr, "Could not find package: %s\n", target)
os.Exit(1)
}
}
template := loadTemplate(document)
var buffer bytes.Buffer
if template == nil {
document.EmitTo(&buffer)
document.EmitSignatureTo(&buffer)
} else {
err := template.Templates()[0].Execute(&buffer, document)
if err != nil {
fmt.Fprintf(os.Stderr, "Error running template: %v", err)
os.Exit(1)
}
document.EmitSignatureTo(&buffer)
}
if debug {
// Skip printing if we're debugging
return
}
documentation := buffer.String()
documentation = strings.TrimSpace(documentation)
if flag_output == "" || flag_output == "-" {
fmt.Println(documentation)
} else {
file, err := os.Create(flag_output)
if err != nil {
}
defer file.Close()
_, err = fmt.Fprintln(file, documentation)
}
}
================================================
FILE: godocdown/main_test.go
================================================
package main
import (
. "./terst"
"bytes"
"path/filepath"
"regexp"
"strings"
"testing"
)
func canTestImport() bool {
have, err := guessImportPath("../example")
Is(err, nil)
return len(have) > 0
}
func testImportPath(target, want string) {
have, err := guessImportPath(fromSlash(target))
Is(err, nil)
if have == "" {
// Probably in a non-standard location, skip the test
return
}
Is(have, want)
}
func TestGuessImportPath(t *testing.T) {
Terst(t)
testImportPath("./example", "github.com/robertkrimen/godocdown/godocdown/example")
testImportPath("../example", "github.com/robertkrimen/godocdown/example")
if filepath.Separator == '/' {
// This test does not work well on windows
testImportPath("/not/in/GOfromSlash", "")
}
testImportPath("in/GOfromSlash", "github.com/robertkrimen/godocdown/godocdown/in/GOfromSlash")
testImportPath(".", "github.com/robertkrimen/godocdown/godocdown")
testImportPath("../example/example", "github.com/robertkrimen/godocdown/example/example")
}
func TestFindTemplate(t *testing.T) {
Terst(t)
Is(findTemplate(fromSlash(".test/godocdown.template")), fromSlash(".test/godocdown.template/.godocdown.template"))
Is(findTemplate(fromSlash(".test/godocdown.tmpl")), fromSlash(".test/godocdown.tmpl/.godocdown.tmpl"))
Is(findTemplate(fromSlash(".test/godocdown.md")), fromSlash(".test/godocdown.md/.godocdown.md"))
Is(findTemplate(fromSlash(".test/godocdown.markdown")), fromSlash(".test/godocdown.markdown/.godocdown.markdown"))
}
func TestIndent(t *testing.T) {
Terst(t)
Is(indent("1\n 2\n\n 3\n 4\n", " "), " 1\n 2\n\n 3\n 4\n")
}
func TestHeadlineSynopsis(t *testing.T) {
Terst(t)
synopsis := `
Headline
The previous line is a single word.
a Title Is Without punctuation
In this mode, a title can be something without punctuation
Also do not title something with a space at the end
Only Title Casing Is Allowed Here
What it says on the tin above.
1word
A title with a-dash
`
is := func(scanner *regexp.Regexp, want string) {
have := headlineSynopsis(synopsis, "#", scanner)
Is(strings.TrimSpace(have), strings.TrimSpace(want))
}
is(synopsisHeading1Word_Regexp, `
# Headline
The previous line is a single word.
a Title Is Without punctuation
In this mode, a title can be something without punctuation
Also do not title something with a space at the end
Only Title Casing Is Allowed Here
What it says on the tin above.
# 1word
A title with a-dash
`)
is(synopsisHeadingTitleCase_Regexp, `
# Headline
The previous line is a single word.
a Title Is Without punctuation
In this mode, a title can be something without punctuation
Also do not title something with a space at the end
# Only Title Casing Is Allowed Here
What it says on the tin above.
1word
A title with a-dash
`)
is(synopsisHeadingTitle_Regexp, `
# Headline
The previous line is a single word.
# a Title Is Without punctuation
In this mode, a title can be something without punctuation
Also do not title something with a space at the end
# Only Title Casing Is Allowed Here
What it says on the tin above.
# 1word
# A title with a-dash
`)
is(synopsisHeadingTitleCase1Word_Regexp, `
# Headline
The previous line is a single word.
a Title Is Without punctuation
In this mode, a title can be something without punctuation
Also do not title something with a space at the end
# Only Title Casing Is Allowed Here
What it says on the tin above.
# 1word
A title with a-dash
`)
}
func Test(t *testing.T) {
Terst(t)
document, err := loadDocument("../example")
if err != nil {
Is(err.Error(), "")
return
}
if document == nil {
Is("200", "404") // Heh
return
}
buffer := bytes.NewBuffer([]byte{})
is := func(want string) {
Is(strings.TrimSpace(buffer.String()), strings.TrimSpace(want))
buffer.Reset()
}
renderHeaderTo(buffer, document)
if canTestImport() {
is("# example\n--\n import \"github.com/robertkrimen/godocdown/example\"")
} else {
is("# example\n--")
}
RenderStyle.IncludeImport = false
renderHeaderTo(buffer, document)
is(`
# example
--
`)
renderSynopsisTo(buffer, document)
is(`
Package example is an example package with documentation
// Here is some code
func example() {
abc := 1 + 1
}()
### Installation
# This is how to install it:
$ curl http://example.com
$ tar xf example.tar.gz -C .
$ ./example &
`)
RenderStyle.IncludeSignature = true
renderSignatureTo(buffer)
is(`
--
**godocdown** http://github.com/robertkrimen/godocdown
`)
renderSignatureTo(buffer)
Is(buffer.String(), "\n\n--\n**godocdown** http://github.com/robertkrimen/godocdown\n")
}
func Test_issue3(t *testing.T) {
Terst(t)
document, err := loadDocument(filepath.Join(".test", "issue3"))
Is(err, nil)
IsNot(document, nil)
buffer := bytes.NewBuffer([]byte{})
document.EmitTo(buffer)
Is(strings.TrimSpace(buffer.String()), strings.TrimSpace(`
# issue3
--
Documentation for package issue3
Nothing happens.
Some code happens.
## Usage
#### func Test
`+"```go\nfunc Test()\n```"+`
Documentation for func Test()
Something happens.
Some code happens.
`))
}
================================================
FILE: godocdown/render.go
================================================
package main
import (
"fmt"
"go/doc"
"io"
)
func renderConstantSectionTo(writer io.Writer, list []*doc.Value) {
for _, entry := range list {
fmt.Fprintf(writer, "%s\n%s\n", indentCode(sourceOfNode(entry.Decl)), formatIndent(filterText(entry.Doc)))
}
}
func renderVariableSectionTo(writer io.Writer, list []*doc.Value) {
for _, entry := range list {
fmt.Fprintf(writer, "%s\n%s\n", indentCode(sourceOfNode(entry.Decl)), formatIndent(filterText(entry.Doc)))
}
}
func renderFunctionSectionTo(writer io.Writer, list []*doc.Func, inTypeSection bool) {
header := RenderStyle.FunctionHeader
if inTypeSection {
header = RenderStyle.TypeFunctionHeader
}
for _, entry := range list {
receiver := " "
if entry.Recv != "" {
receiver = fmt.Sprintf("(%s) ", entry.Recv)
}
fmt.Fprintf(writer, "%s func %s%s\n\n%s\n%s\n", header, receiver, entry.Name, indentCode(sourceOfNode(entry.Decl)), formatIndent(filterText(entry.Doc)))
}
}
func renderTypeSectionTo(writer io.Writer, list []*doc.Type) {
header := RenderStyle.TypeHeader
for _, entry := range list {
fmt.Fprintf(writer, "%s type %s\n\n%s\n\n%s\n", header, entry.Name, indentCode(sourceOfNode(entry.Decl)), formatIndent(filterText(entry.Doc)))
renderConstantSectionTo(writer, entry.Consts)
renderVariableSectionTo(writer, entry.Vars)
renderFunctionSectionTo(writer, entry.Funcs, true)
renderFunctionSectionTo(writer, entry.Methods, true)
}
}
func renderHeaderTo(writer io.Writer, document *_document) {
fmt.Fprintf(writer, "# %s\n--\n", document.Name)
if !document.IsCommand {
// Import
if RenderStyle.IncludeImport {
if document.ImportPath != "" {
fmt.Fprintf(writer, spacer(4)+"import \"%s\"\n\n", document.ImportPath)
}
}
}
}
func renderSynopsisTo(writer io.Writer, document *_document) {
fmt.Fprintf(writer, "%s\n", headifySynopsis(formatIndent(filterText(document.pkg.Doc))))
}
func renderUsageTo(writer io.Writer, document *_document) {
// Usage
fmt.Fprintf(writer, "%s\n", RenderStyle.UsageHeader)
// Constant Section
renderConstantSectionTo(writer, document.pkg.Consts)
// Variable Section
renderVariableSectionTo(writer, document.pkg.Vars)
// Function Section
renderFunctionSectionTo(writer, document.pkg.Funcs, false)
// Type Section
renderTypeSectionTo(writer, document.pkg.Types)
}
func renderSignatureTo(writer io.Writer) {
if RenderStyle.IncludeSignature {
fmt.Fprintf(writer, "\n\n--\n**godocdown** http://github.com/robertkrimen/godocdown\n")
}
}
================================================
FILE: godocdown/terst/terst.go
================================================
// This file was AUTOMATICALLY GENERATED by terst-import from github.com/robertkrimen/terst
/*
Package terst is a terse (terst = test + terse), easy-to-use testing library for Go.
terst is compatible with (and works via) the standard testing package: http://golang.org/pkg/testing
import (
"testing"
. "github.com/robertkrimen/terst"
)
func Test(t *testing.T) {
Terst(t) // Associate terst methods with t (the current testing.T)
Is(getApple(), "apple") // Pass
Is(getOrange(), "orange") // Fail: emits nice-looking diagnostic
Compare(1, ">", 0) // Pass
Compare(1, "==", 1.0) // Pass
}
func getApple() string {
return "apple"
}
func getOrange() string {
return "apple" // Intentional mistake
}
At the top of your testing function, call Terst(), passing the testing.T you receive as the first argument:
func TestExample(t *testing.T) {
Terst(t)
...
}
After you initialize with the given *testing.T, you can use the following to test:
Is
IsNot
Equal
Unequal
IsTrue
IsFalse
Like
Unlike
Compare
Each of the methods above can take an additional (optional) argument,
which is a string describing the test. If the test fails, this
description will be included with the test output For example:
Is(2 + 2, float32(5), "This result is Doubleplusgood")
--- FAIL: Test (0.00 seconds)
test.go:17: This result is Doubleplusgood
Failed test (Is)
got: 4 (int)
expected: 5 (float32)
Future
- Add Catch() for testing panic()
- Add Same() for testing via .DeepEqual && == (without panicking?)
- Add StrictCompare to use {}= scoping
- Add BigCompare for easier math/big.Int testing?
- Support the complex type in Compare()
- Equality test for NaN?
- Better syntax for At*
- Need IsType/TypeIs
*/
package terst
import (
"fmt"
"math/big"
"os"
"reflect"
"regexp"
"runtime"
"strings"
"testing"
"unsafe"
)
func (self *Tester) hadResult(result bool, test *test, onFail func()) bool {
if self.selfTesting {
expect := true
if self.failIsPassing {
expect = false
}
if expect != result {
self.Log(fmt.Sprintf("Expect %v but got %v (%v) (%v) (%v)\n", expect, result, test.kind, test.have, test.want))
onFail()
self._fail()
}
return result
}
if !result {
onFail()
self._fail()
}
return result
}
// IsTrue is DEPRECATED by:
//
// Is(..., true)
//
func IsTrue(have bool, description ...interface{}) bool {
return terstTester().IsTrue(have, description...)
}
// IsTrue is DEPRECATED by:
//
// Is(..., true)
//
func (self *Tester) IsTrue(have bool, description ...interface{}) bool {
return self.trueOrFalse(true, have, description...)
}
// IsFalse is DEPRECATED by:
//
// Is(..., false)
//
func IsFalse(have bool, description ...interface{}) bool {
return terstTester().IsFalse(have, description...)
}
// IsFalse is DEPRECATED by:
//
// Is(..., false)
//
func (self *Tester) IsFalse(have bool, description ...interface{}) bool {
return self.trueOrFalse(false, have, description...)
}
func (self *Tester) trueOrFalse(want bool, have bool, description ...interface{}) bool {
kind := "IsTrue"
if want == false {
kind = "IsFalse"
}
test := newTest(kind, have, want, description)
didPass := have == want
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForIsTrue(test))
})
}
// Fail will fail immediately, reporting a test failure with the (optional) description
func Fail(description ...interface{}) bool {
return terstTester().Fail(description...)
}
// Fail will fail immediately, reporting a test failure with the (optional) description
func (self *Tester) Fail(description ...interface{}) bool {
return self.fail(description...)
}
func (self *Tester) fail(description ...interface{}) bool {
kind := "Fail"
test := newTest(kind, false, false, description)
didPass := false
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForFail(test))
})
}
// FailNow will fail immediately, triggering testing.FailNow() and optionally reporting a test failure with description
func FailNow(description ...interface{}) bool {
return terstTester().FailNow(description...)
}
// FailNow will fail immediately, triggering testing.FailNow() and optionally reporting a test failure with description
func (self *Tester) FailNow(description ...interface{}) bool {
return self.failNow(description...)
}
func (self *Tester) failNow(description ...interface{}) bool {
if len(description) > 0 {
kind := "FailNow"
test := newTest(kind, false, false, description)
didPass := false
self.hadResult(didPass, test, func() {
self.Log(self.failMessageForFail(test))
})
}
self.TestingT.FailNow()
return false
}
// Equal tests have against want via ==:
//
// Equal(have, want) // Pass if have == want
//
// No special coercion or type inspection is done.
//
// If the type is incomparable (e.g. type mismatch) this will panic.
func Equal(have, want interface{}, description ...interface{}) bool {
return terstTester().Equal(have, want, description...)
}
func (self *Tester) Equal(have, want interface{}, description ...interface{}) bool {
return self.equal(have, want, description...)
}
func (self *Tester) equal(have, want interface{}, description ...interface{}) bool {
test := newTest("==", have, want, description)
didPass := have == want
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForEqual(test))
})
}
// Unequal tests have against want via !=:
//
// Unequal(have, want) // Pass if have != want
//
// No special coercion or type inspection is done.
//
// If the type is incomparable (e.g. type mismatch) this will panic.
func Unequal(have, want interface{}, description ...interface{}) bool {
return terstTester().Unequal(have, want, description...)
}
func (self *Tester) Unequal(have, want interface{}, description ...interface{}) bool {
return self.unequal(have, want, description...)
}
func (self *Tester) unequal(have, want interface{}, description ...interface{}) bool {
test := newTest("!=", have, want, description)
didPass := have != want
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForIs(test))
})
}
// Is tests <have> against <want> in different ways, depending on the
// type of <want>.
//
// If <want> is a string, then it will first convert
// <have> to a string before doing the comparison:
//
// Is(fmt.Sprintf("%v", have), want) // Pass if have == want
//
// Otherwise, Is is a shortcut for:
//
// Compare(have, "==", want)
//
// If <want> is a slice, struct, or similar, Is will perform a reflect.DeepEqual() comparison.
func Is(have, want interface{}, description ...interface{}) bool {
return terstTester().Is(have, want, description...)
}
// TODO "slice, struct, or similar" What is similar?
func (self *Tester) Is(have, want interface{}, description ...interface{}) bool {
return self.isOrIsNot(true, have, want, description...)
}
// IsNot tests <have> against <want> in different ways, depending on the
// type of <want>.
//
// If <want> is a string, then it will first convert
// <have> to a string before doing the comparison:
//
// IsNot(fmt.Sprintf("%v", have), want) // Pass if have != want
//
// Otherwise, Is is a shortcut for:
//
// Compare(have, "!=", want)
//
// If <want> is a slice, struct, or similar, Is will perform a reflect.DeepEqual() comparison.
func IsNot(have, want interface{}, description ...interface{}) bool {
return terstTester().IsNot(have, want, description...)
}
// TODO "slice, struct, or similar" What is similar?
func (self *Tester) IsNot(have, want interface{}, description ...interface{}) bool {
return self.isOrIsNot(false, have, want, description...)
}
func (self *Tester) isOrIsNot(wantIs bool, have, want interface{}, description ...interface{}) bool {
test := newTest("Is", have, want, description)
if !wantIs {
test.kind = "IsNot"
}
didPass := false
switch want.(type) {
case string:
didPass = stringValue(have) == want
default:
didPass, _ = compare(have, "{}* ==", want)
}
if !wantIs {
didPass = !didPass
}
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForIs(test))
})
}
// Like tests <have> against <want> in different ways, depending on the
// type of <want>.
//
// If <want> is a string, then it will first convert
// <have> to a string before doing a regular expression comparison:
//
// Like(fmt.Sprintf("%v", have), want) // Pass if regexp.Match(want, have)
//
// Otherwise, Like is a shortcut for:
//
// Compare(have, "{}~ ==", want)
//
// If <want> is a slice, struct, or similar, Like will perform a reflect.DeepEqual() comparison.
func Like(have, want interface{}, description ...interface{}) bool {
return terstTester().Like(have, want, description...)
}
func (self *Tester) Like(have, want interface{}, description ...interface{}) bool {
return self.likeOrUnlike(true, have, want, description...)
}
// Unlike tests <have> against <want> in different ways, depending on the
// type of <want>.
//
// If <want> is a string, then it will first convert
// <have> to a string before doing a regular expression comparison:
//
// Unlike(fmt.Sprintf("%v", have), want) // Pass if !regexp.Match(want, have)
//
// Otherwise, Unlike is a shortcut for:
//
// Compare(have, "{}~ !=", want)
//
// If <want> is a slice, struct, or similar, Unlike will perform a reflect.DeepEqual() comparison.
func Unlike(have, want interface{}, description ...interface{}) bool {
return terstTester().Unlike(have, want, description...)
}
func (self *Tester) Unlike(have, want interface{}, description ...interface{}) bool {
return self.likeOrUnlike(false, have, want, description...)
}
func (self *Tester) likeOrUnlike(wantLike bool, have, want interface{}, description ...interface{}) bool {
test := newTest("Like", have, want, description)
if !wantLike {
test.kind = "Unlike"
}
didPass := false
switch want0 := want.(type) {
case string:
haveString := stringValue(have)
didPass, error := regexp.Match(want0, []byte(haveString))
if !wantLike {
didPass = !didPass
}
if error != nil {
panic("regexp.Match(" + want0 + ", ...): " + error.Error())
}
want = fmt.Sprintf("(?:%v)", want) // Make it look like a regular expression
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForMatch(test, stringValue(have), stringValue(want), wantLike))
})
}
didPass, operator := compare(have, "{}~ ==", want)
if !wantLike {
didPass = !didPass
}
test.operator = operator
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForLike(test, stringValue(have), stringValue(want), wantLike))
})
}
// Compare will compare <have> to <want> with the given operator. The operator can be one of the following:
//
// ==
// !=
// <
// <=
// >
// >=
//
// Compare is not strict when comparing numeric types,
// and will make a best effort to promote <have> and <want> to the
// same type.
//
// Compare will promote int and uint to big.Int for testing
// against each other.
//
// Compare will promote int, uint, and float to float64 for
// float testing.
//
// For example:
//
// Compare(float32(1.0), "<", int8(2)) // A valid test
//
// result := float32(1.0) < int8(2) // Will not compile because of the type mismatch
//
func Compare(have interface{}, operator string, want interface{}, description ...interface{}) bool {
return terstTester().Compare(have, operator, want, description...)
}
func (self *Tester) Compare(have interface{}, operator string, want interface{}, description ...interface{}) bool {
return self.compare(have, operator, want, description...)
}
func (self *Tester) compare(left interface{}, operatorString string, right interface{}, description ...interface{}) bool {
operatorString = strings.TrimSpace(operatorString)
test := newTest("Compare "+operatorString, left, right, description)
didPass, operator := compare(left, operatorString, right)
test.operator = operator
return self.hadResult(didPass, test, func() {
self.Log(self.failMessageForCompare(test))
})
}
type (
compareScope int
)
const (
compareScopeEqual compareScope = iota
compareScopeTilde
compareScopeAsterisk
)
type compareOperator struct {
scope compareScope
comparison string
}
var newCompareOperatorRE *regexp.Regexp = regexp.MustCompile(`^\s*(?:((?:{}|#)[*~=])\s+)?(==|!=|<|<=|>|>=)\s*$`)
func newCompareOperator(operatorString string) compareOperator {
if operatorString == "" {
return compareOperator{compareScopeEqual, ""}
}
result := newCompareOperatorRE.FindStringSubmatch(operatorString)
if result == nil {
panic(fmt.Errorf("Unable to parse %v into a compareOperator", operatorString))
}
scope := compareScopeAsterisk
switch result[1] {
case "#*", "{}*":
scope = compareScopeAsterisk
case "#~", "{}~":
scope = compareScopeTilde
case "#=", "{}=":
scope = compareScopeEqual
}
comparison := result[2]
return compareOperator{scope, comparison}
}
func compare(left interface{}, operatorString string, right interface{}) (bool, compareOperator) {
pass := true
operator := newCompareOperator(operatorString)
comparator := newComparator(left, operator, right)
// FIXME Confusing
switch operator.comparison {
case "==":
pass = comparator.IsEqual()
case "!=":
pass = !comparator.IsEqual()
default:
if comparator.HasOrder() {
switch operator.comparison {
case "<":
pass = comparator.Compare() == -1
case "<=":
pass = comparator.Compare() <= 0
case ">":
pass = comparator.Compare() == 1
case ">=":
pass = comparator.Compare() >= 0
default:
panic(fmt.Errorf("Compare operator (%v) is invalid", operator.comparison))
}
} else {
pass = false
}
}
return pass, operator
}
// Compare / Comparator
type compareKind int
const (
kindInterface compareKind = iota
kindInteger
kindUnsignedInteger
kindFloat
kindString
kindBoolean
)
func comparatorValue(value interface{}) (reflect.Value, compareKind) {
reflectValue := reflect.ValueOf(value)
kind := kindInterface
switch value.(type) {
case int, int8, int16, int32, int64:
kind = kindInteger
case uint, uint8, uint16, uint32, uint64:
kind = kindUnsignedInteger
case float32, float64:
kind = kindFloat
case string:
kind = kindString
case bool:
kind = kindBoolean
}
return reflectValue, kind
}
func toFloat(value reflect.Value) float64 {
switch result := value.Interface().(type) {
case int, int8, int16, int32, int64:
return float64(value.Int())
case uint, uint8, uint16, uint32, uint64:
return float64(value.Uint())
case float32, float64:
return float64(value.Float())
default:
panic(fmt.Errorf("toFloat( %v )", result))
}
panic(0)
}
func toInteger(value reflect.Value) *big.Int {
switch result := value.Interface().(type) {
case int, int8, int16, int32, int64:
return big.NewInt(value.Int())
case uint, uint8, uint16, uint32, uint64:
yield := big.NewInt(0)
yield.SetString(fmt.Sprintf("%v", value.Uint()), 10)
return yield
default:
panic(fmt.Errorf("toInteger( %v )", result))
}
panic(0)
}
func toString(value reflect.Value) string {
switch result := value.Interface().(type) {
case string:
return result
default:
panic(fmt.Errorf("toString( %v )", result))
}
panic(0)
}
func toBoolean(value reflect.Value) bool {
switch result := value.Interface().(type) {
case bool:
return result
default:
panic(fmt.Errorf("toBoolean( %v )", result))
}
panic(0)
}
type aComparator interface {
Compare() int
HasOrder() bool
IsEqual() bool
CompareScope() compareScope
}
type baseComparator struct {
hasOrder bool
operator compareOperator
}
func (self *baseComparator) Compare() int {
panic(fmt.Errorf("Invalid .Compare()"))
}
func (self *baseComparator) HasOrder() bool {
return self.hasOrder
}
func (self *baseComparator) CompareScope() compareScope {
return self.operator.scope
}
func comparatorWithOrder(operator compareOperator) *baseComparator {
return &baseComparator{true, operator}
}
func comparatorWithoutOrder(operator compareOperator) *baseComparator {
return &baseComparator{false, operator}
}
type interfaceComparator struct {
*baseComparator
left interface{}
right interface{}
}
func (self *interfaceComparator) IsEqual() bool {
if self.CompareScope() != compareScopeEqual {
return reflect.DeepEqual(self.left, self.right)
}
return self.left == self.right
}
type floatComparator struct {
*baseComparator
left float64
right float64
}
func (self *floatComparator) Compare() int {
if self.left == self.right {
return 0
} else if self.left < self.right {
return -1
}
return 1
}
func (self *floatComparator) IsEqual() bool {
return self.left == self.right
}
type integerComparator struct {
*baseComparator
left *big.Int
right *big.Int
}
func (self *integerComparator) Compare() int {
return self.left.Cmp(self.right)
}
func (self *integerComparator) IsEqual() bool {
return 0 == self.left.Cmp(self.right)
}
type stringComparator struct {
*baseComparator
left string
right string
}
func (self *stringComparator) Compare() int {
if self.left == self.right {
return 0
} else if self.left < self.right {
return -1
}
return 1
}
func (self *stringComparator) IsEqual() bool {
return self.left == self.right
}
type booleanComparator struct {
*baseComparator
left bool
right bool
}
func (self *booleanComparator) IsEqual() bool {
return self.left == self.right
}
func newComparator(left interface{}, operator compareOperator, right interface{}) aComparator {
leftValue, _ := comparatorValue(left)
rightValue, rightKind := comparatorValue(right)
// The simplest comparator is comparing interface{} =? interface{}
targetKind := kindInterface
// Are left and right of the same kind?
// (reflect.Value.Kind() is different from compareKind)
scopeEqual := leftValue.Kind() == rightValue.Kind()
scopeTilde := false
scopeAsterisk := false
if scopeEqual {
targetKind = rightKind // Since left and right are the same, the targetKind is Integer/Float/String/Boolean
} else {
// Examine the prefix of reflect.Value.Kind().String() to see if there is a similarity of
// the left value to right value
lk := leftValue.Kind().String()
hasPrefix := func(prefix string) bool {
return strings.HasPrefix(lk, prefix)
}
switch right.(type) {
case float32, float64:
// Right is float*
if hasPrefix("float") {
// Left is also float*
targetKind = kindFloat
scopeTilde = true
} else if hasPrefix("int") || hasPrefix("uint") {
// Left is a kind of numeric (int* or uint*)
targetKind = kindFloat
scopeAsterisk = true
} else {
// Otherwise left is a non-numeric
}
case uint, uint8, uint16, uint32, uint64:
// Right is uint*
if hasPrefix("uint") {
// Left is also uint*
targetKind = kindInteger
scopeTilde = true
} else if hasPrefix("int") {
// Left is an int* (a numeric)
targetKind = kindInteger
scopeAsterisk = true
} else if hasPrefix("float") {
// Left is an float* (a numeric)
targetKind = kindFloat
scopeAsterisk = true
} else {
// Otherwise left is a non-numeric
}
case int, int8, int16, int32, int64:
// Right is int*
if hasPrefix("int") {
// Left is also int*
targetKind = kindInteger
scopeTilde = true
} else if hasPrefix("uint") {
// Left is a uint* (a numeric)
targetKind = kindInteger
scopeAsterisk = true
} else if hasPrefix("float") {
// Left is an float* (a numeric)
targetKind = kindFloat
scopeAsterisk = true
} else {
// Otherwise left is a non-numeric
}
default:
// Right is a non-numeric
// Can only really compare string to string or boolean to boolean, so
// we will either have a string/boolean/interfaceComparator
}
}
/*fmt.Println("%v %v %v %v %s %s", operator.scope, same, sibling, family, leftValue, rightValue)*/
{
mismatch := false
switch operator.scope {
case compareScopeEqual:
mismatch = !scopeEqual
case compareScopeTilde:
mismatch = !scopeEqual && !scopeTilde
case compareScopeAsterisk:
mismatch = !scopeEqual && !scopeTilde && !scopeAsterisk
}
if mismatch {
targetKind = kindInterface
}
}
switch targetKind {
case kindFloat:
return &floatComparator{
comparatorWithOrder(operator),
toFloat(leftValue),
toFloat(rightValue),
}
case kindInteger:
return &integerComparator{
comparatorWithOrder(operator),
toInteger(leftValue),
toInteger(rightValue),
}
case kindString:
return &stringComparator{
comparatorWithOrder(operator),
toString(leftValue),
toString(rightValue),
}
case kindBoolean:
return &booleanComparator{
comparatorWithoutOrder(operator),
toBoolean(leftValue),
toBoolean(rightValue),
}
}
// As a last resort, we can always compare left (interface{}) to right (interface{})
return &interfaceComparator{
comparatorWithoutOrder(operator),
left,
right,
}
}
// failMessage*
func (self *Tester) failMessageForIsTrue(test *test) string {
test.findFileLineFunction(self)
return formatMessage(`
%s:%d: %s
Failed test (%s)
got: %s
expected: %s
`, test.file, test.line, test.Description(), test.kind, stringValue(test.have), stringValue(test.want))
}
func (self *Tester) failMessageForFail(test *test) string {
test.findFileLineFunction(self)
return formatMessage(`
%s:%d: %s
Failed test (%s)
`, test.file, test.line, test.Description(), test.kind)
}
func typeKindString(value interface{}) string {
reflectValue := reflect.ValueOf(value)
kind := reflectValue.Kind().String()
result := fmt.Sprintf("%T", value)
if kind == result {
if kind == "string" {
return ""
}
return fmt.Sprintf(" (%T)", value)
}
return fmt.Sprintf(" (%T=%s)", value, kind)
}
func (self *Tester) failMessageForCompare(test *test) string {
test.findFileLineFunction(self)
return formatMessage(`
%s:%d: %s
Failed test (%s)
%v%s
%s
%v%s
`, test.file, test.line, test.Description(), test.kind, test.have, typeKindString(test.have), test.operator.comparison, test.want, typeKindString(test.want))
}
func (self *Tester) failMessageForEqual(test *test) string {
return self.failMessageForIs(test)
}
func (self *Tester) failMessageForIs(test *test) string {
test.findFileLineFunction(self)
return formatMessage(`
%s:%d: %v
Failed test (%s)
got: %v%s
expected: %v%s
`, test.file, test.line, test.Description(), test.kind, test.have, typeKindString(test.have), test.want, typeKindString(test.want))
}
func (self *Tester) failMessageForMatch(test *test, have, want string, wantMatch bool) string {
test.findFileLineFunction(self)
expect := " like"
if !wantMatch {
expect = "unlike"
}
return formatMessage(`
%s:%d: %s
Failed test (%s)
got: %v%s
%s: %s
`, test.file, test.line, test.Description(), test.kind, have, typeKindString(have), expect, want)
}
func (self *Tester) failMessageForLike(test *test, have, want string, wantLike bool) string {
test.findFileLineFunction(self)
if !wantLike {
want = "Anything else"
}
return formatMessage(`
%s:%d: %s
Failed test (%s)
got: %v%s
expected: %v%s
`, test.file, test.line, test.Description(), test.kind, have, typeKindString(have), want, typeKindString(want))
}
// ...
type Tester struct {
TestingT *testing.T
sanityChecking bool
selfTesting bool
failIsPassing bool
testEntry uintptr
focusEntry uintptr
}
var _terstTester *Tester = nil
func findTestEntry() uintptr {
height := 2
for {
functionPC, _, _, ok := runtime.Caller(height)
function := runtime.FuncForPC(functionPC)
functionName := function.Name()
if !ok {
return 0
}
if index := strings.LastIndex(functionName, ".Test"); index >= 0 {
// Assume we have an instance of TestXyzzy in a _test file
return function.Entry()
}
height += 1
}
return 0
}
// Focus will focus the entry point of the test to the current method.
//
// This is important for test failures in getting feedback on which line was at fault.
//
// Consider the following scenario:
//
// func testingMethod( ... ) {
// Is( ..., ... )
// }
//
// func TestExample(t *testing.T) {
// Terst(t)
//
// testingMethod( ... )
// testingMethod( ... ) // If something in testingMethod fails, this line number will come up
// testingMethod( ... )
// }
//
// By default, when a test fails, terst will report the outermost line that led to the failure.
// Usually this is what you want, but if you need to drill down, you can by inserting a special
// call at the top of your testing method:
//
// func testingMethod( ... ) {
// Terst().Focus() // Grab the global Tester and tell it to focus on this method
// Is( ..., ... ) // Now if this test fails, this line number will come up
// }
//
func (self *Tester) Focus() {
pc, _, _, ok := runtime.Caller(1)
if ok {
function := runtime.FuncForPC(pc)
self.focusEntry = function.Entry()
}
}
// Terst(*testing.T)
//
// Create a new terst Tester and return it. Associate calls to Is, Compare, Like, etc. with the newly created terst.
//
// Terst()
//
// Return the current Tester (if any).
//
// Terst(nil)
//
// Clear out the current Tester (if any).
func Terst(terst ...interface{}) *Tester {
if len(terst) == 0 {
return terstTester()
} else {
if terst[0] == nil {
_terstTester = nil
return nil
}
_terstTester = newTester(terst[0].(*testing.T))
_terstTester.enableSanityChecking()
_terstTester.testEntry = findTestEntry()
_terstTester.focusEntry = _terstTester.testEntry
}
return _terstTester
}
func terstTester() *Tester {
if _terstTester == nil {
panic("_terstTester == nil")
}
return _terstTester.checkSanity()
}
func newTester(t *testing.T) *Tester {
return &Tester{
TestingT: t,
}
}
func formatMessage(message string, argumentList ...interface{}) string {
message = fmt.Sprintf(message, argumentList...)
message = strings.TrimLeft(message, "\n")
message = strings.TrimRight(message, " \n")
return message + "\n\n"
}
// Log is a utility method that will append the given output to the normal output stream.
func (self *Tester) Log(output string) {
outputValue := reflect.ValueOf(self.TestingT).Elem().FieldByName("output")
output_ := outputValue.Bytes()
output_ = append(output_, output...)
*(*[]byte)(unsafe.Pointer(outputValue.UnsafeAddr())) = output_
}
func (self *Tester) _fail() {
self.TestingT.Fail()
}
func (self *Tester) enableSanityChecking() *Tester {
self.sanityChecking = true
return self
}
func (self *Tester) disableSanityChecking() *Tester {
self.sanityChecking = false
return self
}
func (self *Tester) enableSelfTesting() *Tester {
self.selfTesting = true
return self
}
func (self *Tester) disableSelfTesting() *Tester {
self.selfTesting = false
return self
}
func (self *Tester) failIsPass() *Tester {
self.failIsPassing = true
return self
}
func (self *Tester) passIsPass() *Tester {
self.failIsPassing = false
return self
}
func (self *Tester) checkSanity() *Tester {
if self.sanityChecking && self.testEntry != 0 {
foundEntryPoint := findTestEntry()
if self.testEntry != foundEntryPoint {
panic(fmt.Errorf("TestEntry(%v) does not match foundEntry(%v): Did you call Terst when entering a new Test* function?", self.testEntry, foundEntryPoint))
}
}
return self
}
func (self *Tester) findDepth() int {
height := 1 // Skip us
for {
pc, _, _, ok := runtime.Caller(height)
function := runtime.FuncForPC(pc)
if !ok {
// Got too close to the sun
if false {
for ; height > 0; height-- {
pc, _, _, ok := runtime.Caller(height)
fmt.Printf("[%d %v %v]", height, pc, ok)
if ok {
function := runtime.FuncForPC(pc)
fmt.Printf(" => [%s]", function.Name())
}
fmt.Printf("\n")
}
}
return 1
}
functionEntry := function.Entry()
if functionEntry == self.focusEntry || functionEntry == self.testEntry {
return height - 1 // Not the surrounding test function, but within it
}
height += 1
}
return 1
}
// test
type test struct {
kind string
have interface{}
want interface{}
description []interface{}
operator compareOperator
file string
line int
functionPC uintptr
function string
}
func newTest(kind string, have, want interface{}, description []interface{}) *test {
operator := newCompareOperator("")
return &test{
kind: kind,
have: have,
want: want,
description: description,
operator: operator,
}
}
func (self *test) findFileLineFunction(tester *Tester) {
self.file, self.line, self.functionPC, self.function, _ = atFileLineFunction(tester.findDepth())
}
func (self *test) Description() string {
description := ""
if len(self.description) > 0 {
description = fmt.Sprintf("%v", self.description[0])
}
return description
}
func findPathForFile(file string) string {
terstBase := os.ExpandEnv("$TERST_BASE")
if len(terstBase) > 0 && strings.HasPrefix(file, terstBase) {
file = file[len(terstBase):]
if file[0] == '/' || file[0] == '\\' {
file = file[1:]
}
return file
}
if index := strings.LastIndex(file, "/"); index >= 0 {
file = file[index+1:]
} else if index = strings.LastIndex(file, "\\"); index >= 0 {
file = file[index+1:]
}
return file
}
func atFileLineFunction(callDepth int) (string, int, uintptr, string, bool) {
pc, file, line, ok := runtime.Caller(callDepth + 1)
function := runtime.FuncForPC(pc).Name()
if ok {
file = findPathForFile(file)
if index := strings.LastIndex(function, ".Test"); index >= 0 {
function = function[index+1:]
}
} else {
pc = 0
file = "?"
line = 1
}
return file, line, pc, function, ok
}
// Conversion
func integerValue(value interface{}) int64 {
return reflect.ValueOf(value).Int()
}
func unsignedIntegerValue(value interface{}) uint64 {
return reflect.ValueOf(value).Uint()
}
func floatValue(value interface{}) float64 {
return reflect.ValueOf(value).Float()
}
func stringValue(value interface{}) string {
return fmt.Sprintf("%v", value)
}
================================================
FILE: godocdown.go
================================================
// Package godocdown is placeholder for the godocdown command
//
// This is a placeholder package, the actual command is:
// http://github.com/robertkrimen/godocdown/godocdown
//
// $ go get http://github.com/robertkrimen/godocdown/godocdown
//
// # Generate documentation, like godoc
// $ godocdown .
//
package godocdown
import (
_ "github.com/robertkrimen/godocdown/godocdown"
)
gitextract_lium6a1f/ ├── .gitignore ├── Makefile ├── README.markdown ├── example/ │ ├── .godocdown.markdown │ └── example.go ├── example.markdown ├── example.template ├── godocdown/ │ ├── .test/ │ │ ├── godocdown.markdown/ │ │ │ ├── .godocdown.markdown │ │ │ ├── .godocdown.md │ │ │ ├── .godocdown.template │ │ │ └── .godocdown.tmpl │ │ ├── godocdown.md/ │ │ │ ├── .godocdown.md │ │ │ ├── .godocdown.template │ │ │ └── .godocdown.tmpl │ │ ├── godocdown.template/ │ │ │ ├── .godocdown.template │ │ │ └── .godocdown.tmpl │ │ ├── godocdown.tmpl/ │ │ │ └── .godocdown.tmpl │ │ └── issue3/ │ │ └── issue3.go │ ├── 7f_shim │ ├── Makefile │ ├── README.markdown │ ├── dbg/ │ │ └── dbg.go │ ├── dbg.go │ ├── go_doc_totext.go │ ├── kilt/ │ │ ├── at.go │ │ ├── exec_command.go │ │ ├── grave_trim.go │ │ ├── kilt.go │ │ ├── print_defaults.go │ │ ├── sha1.go │ │ ├── symlink.go │ │ └── write_atomic_file.go │ ├── kilt.go │ ├── main.go │ ├── main_test.go │ ├── render.go │ └── terst/ │ └── terst.go └── godocdown.go
SYMBOL INDEX (229 symbols across 16 files)
FILE: example/example.go
constant Other (line 20) | Other = 3
constant Another (line 35) | Another = 0
constant Again (line 36) | Again = "this"
function Example (line 40) | func Example() {
type ExampleType (line 51) | type ExampleType struct
method Set (line 61) | func (ExampleType) Set() bool {
function NewExample (line 65) | func NewExample() *ExampleType {
FILE: godocdown/.test/issue3/issue3.go
function Test (line 13) | func Test() {
FILE: godocdown/dbg/dbg.go
type _frmt (line 71) | type _frmt struct
function operandCount (line 85) | func operandCount(format string) int {
function parseFormat (line 103) | func parseFormat(format string) (frmt _frmt) {
type Dbgr (line 132) | type Dbgr struct
method Dbg (line 168) | func (self Dbgr) Dbg(values ...interface{}) {
method Dbgf (line 172) | func (self Dbgr) Dbgf(values ...interface{}) {
method DbgDbgf (line 176) | func (self Dbgr) DbgDbgf() (dbg DbgFunction, dbgf DbgFunction) {
method dbgf (line 186) | func (self Dbgr) dbgf(values ...interface{}) {
method getEmit (line 275) | func (self *Dbgr) getEmit() _emit {
method SetOutput (line 289) | func (self *Dbgr) SetOutput(output interface{}) {
type DbgFunction (line 136) | type DbgFunction
function NewDbgr (line 138) | func NewDbgr() *Dbgr {
function New (line 158) | func New(options ...interface{}) (dbg DbgFunction, dbgf DbgFunction) {
function standardEmit (line 318) | func standardEmit() _emit {
function ln (line 324) | func ln(tmp string) string {
type _emit (line 332) | type _emit interface
type _emitWriter (line 336) | type _emitWriter struct
method emit (line 340) | func (self _emitWriter) emit(frmt _frmt, format string, values ...inte...
type _emitLogger (line 354) | type _emitLogger struct
method emit (line 358) | func (self _emitLogger) emit(frmt _frmt, format string, values ...inte...
type _emitLog (line 372) | type _emitLog struct
method emit (line 375) | func (self _emitLog) emit(frmt _frmt, format string, values ...interfa...
FILE: godocdown/go_doc_totext.go
constant identRx (line 20) | identRx = `[a-zA-Z_][a-zA-Z_0-9]*`
constant protocol (line 23) | protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prosper...
constant hostPart (line 24) | hostPart = `[a-zA-Z0-9_@\-]+`
constant filePart (line 25) | filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
constant urlRx (line 26) | urlRx = protocol + `//` + // http://
function indentLen (line 33) | func indentLen(s string) int {
function isBlank (line 41) | func isBlank(s string) bool {
function commonPrefix (line 45) | func commonPrefix(a, b string) string {
function unindent (line 53) | func unindent(block []string) {
function heading (line 77) | func heading(line string) string {
type op (line 115) | type op
constant opPara (line 118) | opPara op = iota
constant opHead (line 119) | opHead
constant opPre (line 120) | opPre
type block (line 123) | type block struct
function anchorID (line 130) | func anchorID(line string) string {
function blocks (line 135) | func blocks(text string) []block {
function toText (line 215) | func toText(w io.Writer, text string, indent, preIndent string, width in...
type lineWrapper (line 249) | type lineWrapper struct
method write (line 261) | func (l *lineWrapper) write(text string) {
method flush (line 285) | func (l *lineWrapper) flush() {
FILE: godocdown/kilt/at.go
method At (line 10) | func (self Kilt) At(there string, fn func() error) []error {
function At (line 14) | func At(there string, fn func() error) (err []error) {
FILE: godocdown/kilt/exec_command.go
function commandArguments (line 10) | func commandArguments(values ...string) []string {
method ExecCommand (line 21) | func (self Kilt) ExecCommand(program string, arguments ...string) *exec....
function ExecCommand (line 25) | func ExecCommand(program string, arguments ...string) *exec.Cmd {
FILE: godocdown/kilt/grave_trim.go
method GraveTrim (line 9) | func (self Kilt) GraveTrim(target string) string {
function GraveTrim (line 14) | func GraveTrim(target string) string {
FILE: godocdown/kilt/kilt.go
type Kilt (line 5) | type Kilt struct
function New (line 8) | func New() *Kilt {
FILE: godocdown/kilt/print_defaults.go
method PrintDefaults (line 15) | func (self Kilt) PrintDefaults(flag *Flag.FlagSet) {
function PrintDefaults (line 19) | func PrintDefaults(flag *Flag.FlagSet) {
FILE: godocdown/kilt/sha1.go
method Sha1Path (line 14) | func (self Kilt) Sha1Path(path ...string) string {
function Sha1Path (line 18) | func Sha1Path(path ...string) string {
method Sha1Of (line 27) | func (self Kilt) Sha1Of(src io.Reader) string {
function Sha1Of (line 31) | func Sha1Of(src io.Reader) string {
method Sha1 (line 41) | func (self Kilt) Sha1(data []byte) string {
function Sha1 (line 45) | func Sha1(data []byte) string {
FILE: godocdown/kilt/symlink.go
method Symlink (line 10) | func (self Kilt) Symlink(oldname, newname string, overwrite bool) error {
function Symlink (line 14) | func Symlink(oldname, newname string, overwrite bool) error {
FILE: godocdown/kilt/write_atomic_file.go
method WriteAtomicFile (line 14) | func (self Kilt) WriteAtomicFile(filename string, data io.Reader, mode o...
function WriteAtomicFile (line 18) | func WriteAtomicFile(filename string, data io.Reader, mode os.FileMode) ...
FILE: godocdown/main.go
constant punchCardWidth (line 119) | punchCardWidth = 80
constant debug (line 120) | debug = false
function usage (line 170) | func usage() {
function init (line 182) | func init() {
type Style (line 186) | type Style struct
type _document (line 203) | type _document struct
method Emit (line 435) | func (self *_document) Emit() string {
method EmitTo (line 441) | func (self *_document) EmitTo(buffer *bytes.Buffer) {
method EmitSignature (line 458) | func (self *_document) EmitSignature() string {
method EmitSignatureTo (line 464) | func (self *_document) EmitSignatureTo(buffer *bytes.Buffer) {
method EmitHeader (line 472) | func (self *_document) EmitHeader() string {
method EmitHeaderTo (line 478) | func (self *_document) EmitHeaderTo(buffer *bytes.Buffer) {
method EmitSynopsis (line 483) | func (self *_document) EmitSynopsis() string {
method EmitSynopsisTo (line 489) | func (self *_document) EmitSynopsisTo(buffer *bytes.Buffer) {
method EmitUsage (line 494) | func (self *_document) EmitUsage() string {
method EmitUsageTo (line 500) | func (self *_document) EmitUsageTo(buffer *bytes.Buffer) {
function takeOut7f (line 211) | func takeOut7f(input string) string {
function _formatIndent (line 215) | func _formatIndent(target, indent, preIndent string) string {
function spacer (line 221) | func spacer(width int) string {
function formatIndent (line 225) | func formatIndent(target string) string {
function indentCode (line 229) | func indentCode(target string) string {
function headifySynopsis (line 236) | func headifySynopsis(target string) string {
function headlineSynopsis (line 246) | func headlineSynopsis(synopsis, header string, scanner *regexp.Regexp) s...
function sourceOfNode (line 252) | func sourceOfNode(target interface{}) string {
function indent (line 262) | func indent(target string, indent string) string {
function filterText (line 266) | func filterText(input string) string {
function trimSpace (line 275) | func trimSpace(buffer *bytes.Buffer) {
function fromSlash (line 281) | func fromSlash(path string) string {
function buildImport (line 322) | func buildImport(target string) (*build.Package, error) {
function guessImportPath (line 336) | func guessImportPath(target string) (string, error) {
function loadDocument (line 347) | func loadDocument(target string) (*_document, error) {
function emitString (line 427) | func emitString(fn func(*bytes.Buffer)) string {
function findTemplate (line 511) | func findTemplate(path string) string {
function loadTemplate (line 527) | func loadTemplate(document *_document) *Template.Template {
function main (line 550) | func main() {
FILE: godocdown/main_test.go
function canTestImport (line 12) | func canTestImport() bool {
function testImportPath (line 18) | func testImportPath(target, want string) {
function TestGuessImportPath (line 28) | func TestGuessImportPath(t *testing.T) {
function TestFindTemplate (line 42) | func TestFindTemplate(t *testing.T) {
function TestIndent (line 50) | func TestIndent(t *testing.T) {
function TestHeadlineSynopsis (line 56) | func TestHeadlineSynopsis(t *testing.T) {
function Test (line 159) | func Test(t *testing.T) {
function Test_issue3 (line 220) | func Test_issue3(t *testing.T) {
FILE: godocdown/render.go
function renderConstantSectionTo (line 9) | func renderConstantSectionTo(writer io.Writer, list []*doc.Value) {
function renderVariableSectionTo (line 15) | func renderVariableSectionTo(writer io.Writer, list []*doc.Value) {
function renderFunctionSectionTo (line 21) | func renderFunctionSectionTo(writer io.Writer, list []*doc.Func, inTypeS...
function renderTypeSectionTo (line 37) | func renderTypeSectionTo(writer io.Writer, list []*doc.Type) {
function renderHeaderTo (line 50) | func renderHeaderTo(writer io.Writer, document *_document) {
function renderSynopsisTo (line 63) | func renderSynopsisTo(writer io.Writer, document *_document) {
function renderUsageTo (line 67) | func renderUsageTo(writer io.Writer, document *_document) {
function renderSignatureTo (line 84) | func renderSignatureTo(writer io.Writer) {
FILE: godocdown/terst/terst.go
function IsTrue (line 112) | func IsTrue(have bool, description ...interface{}) bool {
function IsFalse (line 128) | func IsFalse(have bool, description ...interface{}) bool {
function Fail (line 153) | func Fail(description ...interface{}) bool {
function FailNow (line 172) | func FailNow(description ...interface{}) bool {
function Equal (line 201) | func Equal(have, want interface{}, description ...interface{}) bool {
function Unequal (line 224) | func Unequal(have, want interface{}, description ...interface{}) bool {
function Is (line 253) | func Is(have, want interface{}, description ...interface{}) bool {
function IsNot (line 276) | func IsNot(have, want interface{}, description ...interface{}) bool {
function Like (line 319) | func Like(have, want interface{}, description ...interface{}) bool {
function Unlike (line 340) | func Unlike(have, want interface{}, description ...interface{}) bool {
function Compare (line 404) | func Compare(have interface{}, operator string, want interface{}, descri...
type compareScope (line 423) | type compareScope
constant compareScopeEqual (line 427) | compareScopeEqual compareScope = iota
constant compareScopeTilde (line 428) | compareScopeTilde
constant compareScopeAsterisk (line 429) | compareScopeAsterisk
type compareOperator (line 432) | type compareOperator struct
function newCompareOperator (line 439) | func newCompareOperator(operatorString string) compareOperator {
function compare (line 465) | func compare(left interface{}, operatorString string, right interface{})...
type compareKind (line 498) | type compareKind
constant kindInterface (line 501) | kindInterface compareKind = iota
constant kindInteger (line 502) | kindInteger
constant kindUnsignedInteger (line 503) | kindUnsignedInteger
constant kindFloat (line 504) | kindFloat
constant kindString (line 505) | kindString
constant kindBoolean (line 506) | kindBoolean
function comparatorValue (line 509) | func comparatorValue(value interface{}) (reflect.Value, compareKind) {
function toFloat (line 527) | func toFloat(value reflect.Value) float64 {
function toInteger (line 541) | func toInteger(value reflect.Value) *big.Int {
function toString (line 555) | func toString(value reflect.Value) string {
function toBoolean (line 565) | func toBoolean(value reflect.Value) bool {
type aComparator (line 575) | type aComparator interface
type baseComparator (line 582) | type baseComparator struct
method Compare (line 587) | func (self *baseComparator) Compare() int {
method HasOrder (line 590) | func (self *baseComparator) HasOrder() bool {
method CompareScope (line 593) | func (self *baseComparator) CompareScope() compareScope {
function comparatorWithOrder (line 596) | func comparatorWithOrder(operator compareOperator) *baseComparator {
function comparatorWithoutOrder (line 599) | func comparatorWithoutOrder(operator compareOperator) *baseComparator {
type interfaceComparator (line 603) | type interfaceComparator struct
method IsEqual (line 609) | func (self *interfaceComparator) IsEqual() bool {
type floatComparator (line 616) | type floatComparator struct
method Compare (line 622) | func (self *floatComparator) Compare() int {
method IsEqual (line 630) | func (self *floatComparator) IsEqual() bool {
type integerComparator (line 634) | type integerComparator struct
method Compare (line 640) | func (self *integerComparator) Compare() int {
method IsEqual (line 643) | func (self *integerComparator) IsEqual() bool {
type stringComparator (line 647) | type stringComparator struct
method Compare (line 653) | func (self *stringComparator) Compare() int {
method IsEqual (line 661) | func (self *stringComparator) IsEqual() bool {
type booleanComparator (line 665) | type booleanComparator struct
method IsEqual (line 671) | func (self *booleanComparator) IsEqual() bool {
function newComparator (line 675) | func newComparator(left interface{}, operator compareOperator, right int...
function typeKindString (line 822) | func typeKindString(value interface{}) string {
type Tester (line 889) | type Tester struct
method hadResult (line 88) | func (self *Tester) hadResult(result bool, test *test, onFail func()) ...
method IsTrue (line 120) | func (self *Tester) IsTrue(have bool, description ...interface{}) bool {
method IsFalse (line 136) | func (self *Tester) IsFalse(have bool, description ...interface{}) bool {
method trueOrFalse (line 140) | func (self *Tester) trueOrFalse(want bool, have bool, description ...i...
method Fail (line 158) | func (self *Tester) Fail(description ...interface{}) bool {
method fail (line 162) | func (self *Tester) fail(description ...interface{}) bool {
method FailNow (line 177) | func (self *Tester) FailNow(description ...interface{}) bool {
method failNow (line 181) | func (self *Tester) failNow(description ...interface{}) bool {
method Equal (line 205) | func (self *Tester) Equal(have, want interface{}, description ...inter...
method equal (line 209) | func (self *Tester) equal(have, want interface{}, description ...inter...
method Unequal (line 228) | func (self *Tester) Unequal(have, want interface{}, description ...int...
method unequal (line 232) | func (self *Tester) unequal(have, want interface{}, description ...int...
method Is (line 259) | func (self *Tester) Is(have, want interface{}, description ...interfac...
method IsNot (line 282) | func (self *Tester) IsNot(have, want interface{}, description ...inter...
method isOrIsNot (line 286) | func (self *Tester) isOrIsNot(wantIs bool, have, want interface{}, des...
method Like (line 323) | func (self *Tester) Like(have, want interface{}, description ...interf...
method Unlike (line 344) | func (self *Tester) Unlike(have, want interface{}, description ...inte...
method likeOrUnlike (line 348) | func (self *Tester) likeOrUnlike(wantLike bool, have, want interface{}...
method Compare (line 408) | func (self *Tester) Compare(have interface{}, operator string, want in...
method compare (line 412) | func (self *Tester) compare(left interface{}, operatorString string, r...
method failMessageForIsTrue (line 804) | func (self *Tester) failMessageForIsTrue(test *test) string {
method failMessageForFail (line 814) | func (self *Tester) failMessageForFail(test *test) string {
method failMessageForCompare (line 835) | func (self *Tester) failMessageForCompare(test *test) string {
method failMessageForEqual (line 846) | func (self *Tester) failMessageForEqual(test *test) string {
method failMessageForIs (line 850) | func (self *Tester) failMessageForIs(test *test) string {
method failMessageForMatch (line 860) | func (self *Tester) failMessageForMatch(test *test, have, want string,...
method failMessageForLike (line 874) | func (self *Tester) failMessageForLike(test *test, have, want string, ...
method Focus (line 947) | func (self *Tester) Focus() {
method Log (line 1003) | func (self *Tester) Log(output string) {
method _fail (line 1010) | func (self *Tester) _fail() {
method enableSanityChecking (line 1014) | func (self *Tester) enableSanityChecking() *Tester {
method disableSanityChecking (line 1019) | func (self *Tester) disableSanityChecking() *Tester {
method enableSelfTesting (line 1024) | func (self *Tester) enableSelfTesting() *Tester {
method disableSelfTesting (line 1029) | func (self *Tester) disableSelfTesting() *Tester {
method failIsPass (line 1034) | func (self *Tester) failIsPass() *Tester {
method passIsPass (line 1039) | func (self *Tester) passIsPass() *Tester {
method checkSanity (line 1044) | func (self *Tester) checkSanity() *Tester {
method findDepth (line 1054) | func (self *Tester) findDepth() int {
function findTestEntry (line 902) | func findTestEntry() uintptr {
function Terst (line 966) | func Terst(terst ...interface{}) *Tester {
function terstTester (line 982) | func terstTester() *Tester {
function newTester (line 989) | func newTester(t *testing.T) *Tester {
function formatMessage (line 995) | func formatMessage(message string, argumentList ...interface{}) string {
type test (line 1085) | type test struct
method findFileLineFunction (line 1109) | func (self *test) findFileLineFunction(tester *Tester) {
method Description (line 1113) | func (self *test) Description() string {
function newTest (line 1098) | func newTest(kind string, have, want interface{}, description []interfac...
function findPathForFile (line 1121) | func findPathForFile(file string) string {
function atFileLineFunction (line 1140) | func atFileLineFunction(callDepth int) (string, int, uintptr, string, bo...
function integerValue (line 1158) | func integerValue(value interface{}) int64 {
function unsignedIntegerValue (line 1162) | func unsignedIntegerValue(value interface{}) uint64 {
function floatValue (line 1166) | func floatValue(value interface{}) float64 {
function stringValue (line 1170) | func stringValue(value interface{}) string {
Condensed preview — 38 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (111K chars).
[
{
"path": ".gitignore",
"chars": 21,
"preview": "/godocdown/godocdown\n"
},
{
"path": "Makefile",
"chars": 292,
"preview": ".PHONY: build test install release\n\nbuild test install:\n\t$(MAKE) -C godocdown $@\n\nrelease: build\n\tgodocdown/godocdown -t"
},
{
"path": "README.markdown",
"chars": 3387,
"preview": "# godocdown\n--\nCommand godocdown generates Go documentation in a GitHub-friendly Markdown\nformat.\n\n $ go get github.c"
},
{
"path": "example/.godocdown.markdown",
"chars": 60,
"preview": "{{ .Emit }}\n\n{{ .EmitSignature }}\n\n--\nThis was via template\n"
},
{
"path": "example/example.go",
"chars": 897,
"preview": "/*\nPackage example is an example package with documentation \n\n\t// Here is some code\n\tfunc example() {\n\t\tabc := 1 + 1\n\t}("
},
{
"path": "example.markdown",
"chars": 11957,
"preview": "# Example godocdown (strings)\n\nThis markdown was generated with the help of custom template file ([example.template](htt"
},
{
"path": "example.template",
"chars": 1492,
"preview": "# Example godocdown (strings)\n\nThis markdown was generated with the help of custom template file ([example.template](htt"
},
{
"path": "godocdown/.test/godocdown.markdown/.godocdown.markdown",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.markdown/.godocdown.md",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.markdown/.godocdown.template",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.markdown/.godocdown.tmpl",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.md/.godocdown.md",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.md/.godocdown.template",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.md/.godocdown.tmpl",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.template/.godocdown.template",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.template/.godocdown.tmpl",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/godocdown.tmpl/.godocdown.tmpl",
"chars": 0,
"preview": ""
},
{
"path": "godocdown/.test/issue3/issue3.go",
"chars": 213,
"preview": "// Documentation for package issue3\n//\n// Nothing happens.\n//\n// Some code happens.\npackage issue3\n\n// Documenta"
},
{
"path": "godocdown/7f_shim",
"chars": 374,
"preview": "#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\n\nmy @input = <STDIN>;\nmy $longest = 0;\nfor (@input) {\n chomp;\n s/\\s"
},
{
"path": "godocdown/Makefile",
"chars": 272,
"preview": ".PHONY: build test test-example install release\n\nbuild: test\n\tgo build\n\ntest:\n\tgo test -i\n\tgo test\n\ntest-example: build\n"
},
{
"path": "godocdown/README.markdown",
"chars": 3387,
"preview": "# godocdown\n--\nCommand godocdown generates Go documentation in a GitHub-friendly Markdown\nformat.\n\n $ go get github.c"
},
{
"path": "godocdown/dbg/dbg.go",
"chars": 8446,
"preview": "// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) from github.com/robertkrimen/dbg\n\n/*\nPackage dbg is a p"
},
{
"path": "godocdown/dbg.go",
"chars": 205,
"preview": "// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg\n\npackage main\n\nimport ("
},
{
"path": "godocdown/go_doc_totext.go",
"chars": 5855,
"preview": "package main\n\n// Our own, slightly different version of ToText.\n\nimport (\n\t\"io\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unicod"
},
{
"path": "godocdown/kilt/at.go",
"chars": 689,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/exec_command.go",
"chars": 640,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/grave_trim.go",
"chars": 877,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/kilt.go",
"chars": 174,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\ntype "
},
{
"path": "godocdown/kilt/print_defaults.go",
"chars": 592,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/sha1.go",
"chars": 852,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/symlink.go",
"chars": 786,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt/write_atomic_file.go",
"chars": 952,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) from github.com/robertkrimen/kilt\n\npackage kilt\n\nimpor"
},
{
"path": "godocdown/kilt.go",
"chars": 205,
"preview": "// This file was AUTOMATICALLY GENERATED by kilt-import (smuggol) for github.com/robertkrimen/kilt\n\npackage main\n\nimport"
},
{
"path": "godocdown/main.go",
"chars": 19845,
"preview": "/*\nCommand godocdown generates Go documentation in a GitHub-friendly Markdown format.\n\n $ go get github.com/robertkri"
},
{
"path": "godocdown/main_test.go",
"chars": 5151,
"preview": "package main\n\nimport (\n\t. \"./terst\"\n\t\"bytes\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc canTestImport() bo"
},
{
"path": "godocdown/render.go",
"chars": 2496,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"go/doc\"\n\t\"io\"\n)\n\nfunc renderConstantSectionTo(writer io.Writer, list []*doc.Value) {\n\tfo"
},
{
"path": "godocdown/terst/terst.go",
"chars": 30259,
"preview": "// This file was AUTOMATICALLY GENERATED by terst-import from github.com/robertkrimen/terst\n\n/* \nPackage terst is a ters"
},
{
"path": "godocdown.go",
"chars": 399,
"preview": "// Package godocdown is placeholder for the godocdown command\n//\n// This is a placeholder package, the actual command is"
}
]
About this extraction
This page contains the full source code of the robertkrimen/godocdown GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 38 files (98.4 KB), approximately 27.4k tokens, and a symbol index with 229 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.