├── .github ├── FUNDING.yml └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── README.md ├── autocomplete.go ├── autocomplete_test.go ├── docs └── example.gif ├── generator.go ├── go.mod ├── go.sum ├── main.go ├── manager.go ├── manager_test.go ├── parser.go ├── parser_test.go ├── scripts ├── fetcher.go └── visiter.go └── template.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ahmedakef 2 | ko_fi: ahmedakef 3 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a golang project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go 3 | 4 | name: Go 5 | 6 | on: 7 | push: 8 | branches: [ "main" ] 9 | pull_request: 10 | branches: [ "main" ] 11 | 12 | jobs: 13 | 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v4 21 | with: 22 | go-version: '1.20' 23 | 24 | - name: Install goimports 25 | run: go install golang.org/x/tools/cmd/goimports@latest 26 | 27 | - name: Build 28 | run: go build -v ./... 29 | 30 | - name: Test 31 | run: go test -v ./... 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | goshell 2 | bin 3 | program.go 4 | .vscode 5 | scripts/pkgNames.json 6 | scripts/pkgFunctions.json 7 | scripts/listResponse.html 8 | scripts/detailsResponse.html 9 | .DS_Store 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ahmedakef 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Goshell 2 | 3 | Goshell is REPL shell for golang. 4 | 5 | the project is inspired by [rango](https://github.com/emicklei/rango/) but took different decisions. 6 | 7 | ## Table of Contents 8 | 9 | - [Installation](#installation) 10 | - [Features](#features) 11 | - [Examples](#examples) 12 | - [Contact](#contact) 13 | 14 | ## Installation 15 | 16 | ```sh 17 | go install github.com/ahmedakef/goshell@latest 18 | ``` 19 | ## Features 20 | 21 | - auto import the needed libraries using `goimports` just write `fmt.Print()` and `fmt` will be imported. 22 | - autocompletion for languages keywords and libraries's functions and types without the need for language server. 23 | - print the variablles by writing them, no need to use `fmt.Print()` 24 | - supports all shell line editing commands supported by [liner](https://github.com/peterh/liner?tab=readme-ov-file#line-editing) 25 | - don't have dependancy on goimports 26 | 27 | ## Examples 28 | 29 | ## live demo 30 | ![Example Demo](docs/example.gif?raw=true "Example demo") 31 | 32 | ### Simple variable printing 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 77 | 78 |
code you writegenerated code
45 | 46 | ```go 47 | >>> a:=1 48 | >>> b:=2 49 | >>> a 50 | 1 51 | ``` 52 | 53 | 55 | 56 | ```go 57 | package main 58 | 59 | import "fmt" 60 | 61 | func main() { 62 | a := 1 63 | b := 2 64 | fmt.Println(a) 65 | use(a, b) 66 | } 67 | 68 | // used to avoid "declared and not used" error 69 | func use(vals ...any) { 70 | for _, val := range vals { 71 | _ = val 72 | } 73 | } 74 | ``` 75 | 76 |
3 lines17 lines
79 | 80 | 81 | ### Calling functions 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 106 | 133 | 134 |
code you writegenerated code
94 | 95 | ```go 96 | >>> func add(x,y int) int { 97 | ... return x+y 98 | ... } 99 | >>> a:=1 100 | >>> b:=2 101 | >>> add(a,b) 102 | 3 103 | ``` 104 | 105 | 107 | 108 | ```go 109 | package main 110 | 111 | import "fmt" 112 | 113 | func add(x, y int) int { 114 | return x + y 115 | } 116 | 117 | func main() { 118 | a := 1 119 | b := 2 120 | fmt.Println(add(a, b)) 121 | use(a, b) 122 | } 123 | 124 | // used to avoid "declared and not used" error 125 | func use(vals ...any) { 126 | for _, val := range vals { 127 | _ = val 128 | } 129 | } 130 | ``` 131 | 132 |
6 lines21 lines
135 | 136 | ## Contact 137 | 138 | ahmedakef - aemed.akef.1@gmail.com 139 | -------------------------------------------------------------------------------- /autocomplete.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | 6 | "golang.org/x/exp/maps" 7 | ) 8 | 9 | func WordCompleter(line string, pos int) (head string, completions []string, tail string) { 10 | head = line[:pos] 11 | tail = line[pos:] 12 | if head == "" { 13 | return 14 | } 15 | 16 | lastToken, lastTokenPos := getLastToken(head) 17 | head = head[:lastTokenPos] 18 | 19 | headSplitted := strings.SplitN(lastToken, ".", 2) 20 | packageName := headSplitted[0] 21 | 22 | if !contains(supportedPackages, packageName) { 23 | // this is a not known package, we match to the language keywords 24 | completions = getPossipleSuggestions(autoComplete, packageName) 25 | if len(completions) == 0 { 26 | head += lastToken 27 | } 28 | return 29 | } 30 | 31 | packagePart := packageName + "." 32 | head = head + packagePart 33 | function := "" 34 | 35 | allPkgFunctions := packageFunctions[packageName] 36 | if len(headSplitted) == 2 { 37 | function = headSplitted[1] 38 | if function == "" { 39 | completions = allPkgFunctions 40 | return 41 | } 42 | } 43 | 44 | completions = getPossipleSuggestions(allPkgFunctions, function) 45 | if len(completions) == 0 { 46 | head = lastToken 47 | } 48 | return 49 | } 50 | 51 | func getPossipleSuggestions(possibleWords []string, word string) []string { 52 | var completions []string 53 | for _, possibleWord := range possibleWords { 54 | if strings.HasPrefix(strings.ToLower(possibleWord), strings.ToLower(word)) { 55 | completions = append(completions, possibleWord) 56 | } 57 | } 58 | return completions 59 | } 60 | 61 | func getLastToken(head string) (token string, pos int) { 62 | headSplitted := strings.Split(head, " ") 63 | token = headSplitted[len(headSplitted)-1] 64 | pos = len(head) - len(token) 65 | return 66 | } 67 | 68 | func contains(arr []string, str string) bool { 69 | for _, a := range arr { 70 | if a == str { 71 | return true 72 | } 73 | } 74 | return false 75 | } 76 | 77 | var ( 78 | 79 | // populated using scipts/fetcher.go 80 | 81 | packageFunctions = map[string][]string{"archive/tar": {"Format", "Header", "FileInfoHeader", "Reader", "NewReader", "Writer", "NewWriter"}, 82 | "archive/zip": {"RegisterCompressor", "RegisterDecompressor", "Compressor", "Decompressor", "File", "FileHeader", "FileInfoHeader", "ReadCloser", "OpenReader", "Reader", "NewReader", "Writer", "NewWriter"}, 83 | "bufio": {"ScanBytes", "ScanLines", "ScanRunes", "ScanWords", "ReadWriter", "NewReadWriter", "Reader", "NewReader", "NewReaderSize", "Scanner", "NewScanner", "SplitFunc", "Writer", "NewWriter", "NewWriterSize"}, 84 | "builtin": {"append", "cap", "clear", "close", "complex", "copy", "delete", "imag", "len", "make", "max", "min", "new", "panic", "print", "println", "real", "recover", "ComplexType", "FloatType", "IntegerType", "Type", "Type1", "any", "bool", "byte", "comparable", "complex128", "complex64", "error", "float32", "float64", "int", "int16", "int32", "int64", "int8", "rune", "string", "uint", "uint16", "uint32", "uint64", "uint8", "uintptr"}, 85 | "bytes": {"Clone", "Compare", "Contains", "ContainsAny", "ContainsFunc", "ContainsRune", "Count", "Cut", "CutPrefix", "CutSuffix", "Equal", "EqualFold", "Fields", "FieldsFunc", "HasPrefix", "HasSuffix", "Index", "IndexAny", "IndexByte", "IndexFunc", "IndexRune", "Join", "LastIndex", "LastIndexAny", "LastIndexByte", "LastIndexFunc", "Map", "Repeat", "Replace", "ReplaceAll", "Runes", "Split", "SplitAfter", "SplitAfterN", "SplitN", "Title", "ToLower", "ToLowerSpecial", "ToTitle", "ToTitleSpecial", "ToUpper", "ToUpperSpecial", "ToValidUTF8", "Trim", "TrimFunc", "TrimLeft", "TrimLeftFunc", "TrimPrefix", "TrimRight", "TrimRightFunc", "TrimSpace", "TrimSuffix", "Buffer", "NewBuffer", "NewBufferString", "Reader", "NewReader"}, 86 | "cmp": {"Compare", "Less", "Or", "Ordered"}, 87 | "compress/bzip2": {"NewReader", "StructuralError"}, 88 | "compress/flate": {"NewReader", "NewReaderDict", "CorruptInputError", "InternalError", "ReadError", "Reader", "Resetter", "WriteError", "Writer", "NewWriter", "NewWriterDict"}, 89 | "compress/gzip": {"Header", "Reader", "NewReader", "Writer", "NewWriter", "NewWriterLevel"}, 90 | "compress/lzw": {"NewReader", "NewWriter", "Order", "Reader", "Writer"}, 91 | "compress/zlib": {"NewReader", "NewReaderDict", "Resetter", "Writer", "NewWriter", "NewWriterLevel", "NewWriterLevelDict"}, 92 | "container/heap": {"Fix", "Init", "Pop", "Push", "Remove", "Interface"}, 93 | "container/list": {"Element", "List", "New"}, 94 | "container/ring": {"Ring", "New"}, 95 | "context": {"AfterFunc", "Cause", "WithCancel", "WithCancelCause", "WithDeadline", "WithDeadlineCause", "WithTimeout", "WithTimeoutCause", "CancelCauseFunc", "CancelFunc", "Context", "Background", "TODO", "WithValue", "WithoutCancel"}, 96 | "crypto": {"RegisterHash", "Decrypter", "DecrypterOpts", "Hash", "PrivateKey", "PublicKey", "Signer", "SignerOpts"}, 97 | "crypto/aes": {"NewCipher", "KeySizeError"}, 98 | "crypto/cipher": {"AEAD", "NewGCM", "NewGCMWithNonceSize", "NewGCMWithTagSize", "Block", "BlockMode", "NewCBCDecrypter", "NewCBCEncrypter", "Stream", "NewCFBDecrypter", "NewCFBEncrypter", "NewCTR", "NewOFB", "StreamReader", "StreamWriter"}, 99 | "crypto/des": {"NewCipher", "NewTripleDESCipher", "KeySizeError"}, 100 | "crypto/dsa": {"GenerateKey", "GenerateParameters", "Sign", "Verify", "ParameterSizes", "Parameters", "PrivateKey", "PublicKey"}, 101 | "crypto/ecdh": {"Curve", "P256", "P384", "P521", "X25519", "PrivateKey", "PublicKey"}, 102 | "crypto/ecdsa": {"Sign", "SignASN1", "Verify", "VerifyASN1", "PrivateKey", "GenerateKey", "PublicKey"}, 103 | "crypto/ed25519": {"GenerateKey", "Sign", "Verify", "VerifyWithOptions", "Options", "PrivateKey", "NewKeyFromSeed", "PublicKey"}, 104 | "crypto/elliptic": {"GenerateKey", "Marshal", "MarshalCompressed", "Unmarshal", "UnmarshalCompressed", "Curve", "P224", "P256", "P384", "P521", "CurveParams"}, 105 | "crypto/hmac": {"Equal", "New"}, 106 | "crypto/internal/alias": {"AnyOverlap", "InexactOverlap"}, 107 | "crypto/internal/bigmod": {"Modulus", "NewModulusFromBig", "Nat", "NewNat"}, 108 | "crypto/internal/boring": {"DecryptRSANoPadding", "DecryptRSAOAEP", "DecryptRSAPKCS1", "ECDH", "EncryptRSANoPadding", "EncryptRSAOAEP", "EncryptRSAPKCS1", "NewAESCipher", "NewGCMTLS", "NewHMAC", "NewSHA1", "NewSHA224", "NewSHA256", "NewSHA384", "NewSHA512", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SignMarshalECDSA", "SignRSAPKCS1v15", "SignRSAPSS", "Unreachable", "UnreachableExceptTests", "VerifyECDSA", "VerifyRSAPKCS1v15", "VerifyRSAPSS", "BigInt", "GenerateKeyECDSA", "GenerateKeyRSA", "PrivateKeyECDH", "GenerateKeyECDH", "NewPrivateKeyECDH", "PublicKey", "PrivateKeyECDSA", "NewPrivateKeyECDSA", "PrivateKeyRSA", "NewPrivateKeyRSA", "PublicKeyECDH", "NewPublicKeyECDH", "Bytes", "PublicKeyECDSA", "NewPublicKeyECDSA", "PublicKeyRSA", "NewPublicKeyRSA"}, 109 | "crypto/internal/boring/bbig": {"Dec", "Enc"}, 110 | "crypto/internal/boring/bcache": {"Cache"}, 111 | "crypto/internal/boring/sig": {"BoringCrypto", "FIPSOnly", "StandardCrypto"}, 112 | "crypto/internal/edwards25519": {"Point", "NewGeneratorPoint", "NewIdentityPoint", "Scalar", "NewScalar"}, 113 | "crypto/internal/edwards25519/field": {"Element"}, 114 | "crypto/internal/nistec": {"P256OrdInverse", "P224Point", "NewP224Point", "P256Point", "NewP256Point", "P384Point", "NewP384Point", "P521Point", "NewP521Point"}, 115 | "crypto/internal/nistec/fiat": {"P224Element", "P256Element", "P384Element", "P521Element"}, 116 | "crypto/internal/randutil": {"MaybeReadByte"}, 117 | "crypto/md5": {"New", "Sum"}, 118 | "crypto/rand": {"Int", "Prime", "Read"}, 119 | "crypto/rc4": {"Cipher", "NewCipher", "KeySizeError"}, 120 | "crypto/rsa": {"DecryptOAEP", "DecryptPKCS1v15", "DecryptPKCS1v15SessionKey", "EncryptOAEP", "EncryptPKCS1v15", "SignPKCS1v15", "SignPSS", "VerifyPKCS1v15", "VerifyPSS", "CRTValue", "OAEPOptions", "PKCS1v15DecryptOptions", "PSSOptions", "PrecomputedValues", "PrivateKey", "GenerateKey", "GenerateMultiPrimeKey", "PublicKey"}, 121 | "crypto/sha1": {"New", "Sum"}, 122 | "crypto/sha256": {"New", "New224", "Sum224", "Sum256"}, 123 | "crypto/sha512": {"New", "New384", "New512_224", "New512_256", "Sum384", "Sum512", "Sum512_224", "Sum512_256"}, 124 | "crypto/subtle": {"ConstantTimeByteEq", "ConstantTimeCompare", "ConstantTimeCopy", "ConstantTimeEq", "ConstantTimeLessOrEq", "ConstantTimeSelect", "XORBytes"}, 125 | "crypto/tls": {"CipherSuiteName", "Listen", "NewListener", "VersionName", "AlertError", "Certificate", "LoadX509KeyPair", "X509KeyPair", "CertificateRequestInfo", "CertificateVerificationError", "CipherSuite", "CipherSuites", "InsecureCipherSuites", "ClientAuthType", "ClientHelloInfo", "ClientSessionCache", "NewLRUClientSessionCache", "ClientSessionState", "NewResumptionState", "Config", "Conn", "Client", "Dial", "DialWithDialer", "Server", "ConnectionState", "CurveID", "Dialer", "QUICConfig", "QUICConn", "QUICClient", "QUICServer", "QUICEncryptionLevel", "QUICEvent", "QUICEventKind", "QUICSessionTicketOptions", "RecordHeaderError", "RenegotiationSupport", "SessionState", "ParseSessionState", "SignatureScheme"}, 126 | "crypto/x509": {"CreateCertificate", "CreateCertificateRequest", "CreateRevocationList", "DecryptPEMBlock", "EncryptPEMBlock", "IsEncryptedPEMBlock", "MarshalECPrivateKey", "MarshalPKCS1PrivateKey", "MarshalPKCS1PublicKey", "MarshalPKCS8PrivateKey", "MarshalPKIXPublicKey", "ParseCRL", "ParseDERCRL", "ParseECPrivateKey", "ParsePKCS1PrivateKey", "ParsePKCS1PublicKey", "ParsePKCS8PrivateKey", "ParsePKIXPublicKey", "SetFallbackRoots", "CertPool", "NewCertPool", "SystemCertPool", "Certificate", "ParseCertificate", "ParseCertificates", "CertificateInvalidError", "CertificateRequest", "ParseCertificateRequest", "ConstraintViolationError", "Error", "ExtKeyUsage", "HostnameError", "InsecureAlgorithmError", "InvalidReason", "KeyUsage", "OID", "OIDFromInts", "PEMCipher", "PublicKeyAlgorithm", "RevocationList", "ParseRevocationList", "RevocationListEntry", "SignatureAlgorithm", "SystemRootsError", "UnhandledCriticalExtension", "UnknownAuthorityError", "VerifyOptions"}, 127 | "crypto/x509/internal/macos": {"CFArrayAppendValue", "CFArrayGetCount", "CFDataGetBytePtr", "CFDataGetLength", "CFDataToSlice", "CFEqual", "CFErrorGetCode", "CFNumberGetValue", "CFRelease", "CFStringToString", "ReleaseCFArray", "SecCertificateCopyData", "SecTrustEvaluateWithError", "SecTrustGetCertificateCount", "SecTrustGetResult", "SecTrustSetVerifyDate", "CFRef", "BytesToCFData", "CFArrayCreateMutable", "CFArrayGetValueAtIndex", "CFDateCreate", "CFDictionaryGetValueIfPresent", "CFErrorCopyDescription", "CFStringCreateExternalRepresentation", "SecCertificateCreateWithData", "SecPolicyCreateSSL", "SecTrustCreateWithCertificates", "SecTrustEvaluate", "SecTrustGetCertificateAtIndex", "SecTrustSettingsCopyCertificates", "SecTrustSettingsCopyTrustSettings", "TimeToCFDateRef", "CFString", "StringToCFString", "OSStatus", "SecTrustResultType", "SecTrustSettingsDomain", "SecTrustSettingsResult"}, 128 | "crypto/x509/pkix": {"AlgorithmIdentifier", "AttributeTypeAndValue", "AttributeTypeAndValueSET", "CertificateList", "Extension", "Name", "RDNSequence", "RelativeDistinguishedNameSET", "RevokedCertificate", "TBSCertificateList"}, 129 | "database/sql": {"Drivers", "Register", "ColumnType", "Conn", "DB", "Open", "OpenDB", "DBStats", "IsolationLevel", "NamedArg", "Named", "Null", "NullBool", "NullByte", "NullFloat64", "NullInt16", "NullInt32", "NullInt64", "NullString", "NullTime", "Out", "RawBytes", "Result", "Row", "Rows", "Scanner", "Stmt", "Tx", "TxOptions"}, 130 | "database/sql/driver": {"IsScanValue", "IsValue", "ColumnConverter", "Conn", "ConnBeginTx", "ConnPrepareContext", "Connector", "Driver", "DriverContext", "Execer", "ExecerContext", "IsolationLevel", "NamedValue", "NamedValueChecker", "NotNull", "Null", "Pinger", "Queryer", "QueryerContext", "Result", "Rows", "RowsAffected", "LastInsertId", "RowsColumnTypeDatabaseTypeName", "RowsColumnTypeLength", "RowsColumnTypeNullable", "RowsColumnTypePrecisionScale", "RowsColumnTypeScanType", "RowsNextResultSet", "SessionResetter", "Stmt", "StmtExecContext", "StmtQueryContext", "Tx", "TxOptions", "Validator", "Value", "ValueConverter", "Valuer"}, 131 | "debug/buildinfo": {"BuildInfo", "Read", "ReadFile"}, 132 | "debug/dwarf": {"AddrType", "ArrayType", "Attr", "BasicType", "BoolType", "CharType", "Class", "CommonType", "ComplexType", "Data", "New", "DecodeError", "DotDotDotType", "Entry", "EnumType", "EnumValue", "Field", "FloatType", "FuncType", "IntType", "LineEntry", "LineFile", "LineReader", "LineReaderPos", "Offset", "PtrType", "QualType", "Reader", "StructField", "StructType", "Tag", "Type", "TypedefType", "UcharType", "UintType", "UnspecifiedType", "UnsupportedType", "VoidType"}, 133 | "debug/elf": {"R_INFO", "R_INFO32", "R_SYM32", "R_SYM64", "R_TYPE32", "R_TYPE64", "ST_INFO", "Chdr32", "Chdr64", "Class", "CompressionType", "Data", "Dyn32", "Dyn64", "DynFlag", "DynFlag1", "DynTag", "File", "NewFile", "Open", "FileHeader", "FormatError", "Header32", "Header64", "ImportedSymbol", "Machine", "NType", "OSABI", "Prog", "Prog32", "Prog64", "ProgFlag", "ProgHeader", "ProgType", "R_386", "R_390", "R_AARCH64", "R_ALPHA", "R_ARM", "R_LARCH", "R_MIPS", "R_PPC", "R_PPC64", "R_RISCV", "R_SPARC", "R_X86_64", "Rel32", "Rel64", "Rela32", "Rela64", "Section", "Section32", "Section64", "SectionFlag", "SectionHeader", "SectionIndex", "SectionType", "Sym32", "Sym64", "SymBind", "ST_BIND", "SymType", "ST_TYPE", "SymVis", "ST_VISIBILITY", "Symbol", "Type", "Version"}, 134 | "debug/gosym": {"DecodingError", "Func", "LineTable", "NewLineTable", "Obj", "Sym", "Table", "NewTable", "UnknownFileError", "UnknownLineError"}, 135 | "debug/macho": {"Cpu", "Dylib", "DylibCmd", "Dysymtab", "DysymtabCmd", "FatArch", "FatArchHeader", "FatFile", "NewFatFile", "OpenFat", "File", "NewFile", "Open", "FileHeader", "FormatError", "Load", "LoadBytes", "LoadCmd", "Nlist32", "Nlist64", "Regs386", "RegsAMD64", "Reloc", "RelocTypeARM", "RelocTypeARM64", "RelocTypeGeneric", "RelocTypeX86_64", "Rpath", "RpathCmd", "Section", "Section32", "Section64", "SectionHeader", "Segment", "Segment32", "Segment64", "SegmentHeader", "Symbol", "Symtab", "SymtabCmd", "Thread", "Type"}, 136 | "debug/pe": {"COFFSymbol", "COFFSymbolAuxFormat5", "DataDirectory", "File", "NewFile", "Open", "FileHeader", "FormatError", "ImportDirectory", "OptionalHeader32", "OptionalHeader64", "Reloc", "Section", "SectionHeader", "SectionHeader32", "StringTable", "Symbol"}, 137 | "debug/plan9obj": {"File", "NewFile", "Open", "FileHeader", "Section", "SectionHeader", "Sym"}, 138 | "embed": {"FS"}, 139 | "encoding": {"BinaryMarshaler", "BinaryUnmarshaler", "TextMarshaler", "TextUnmarshaler"}, 140 | "encoding/ascii85": {"Decode", "Encode", "MaxEncodedLen", "NewDecoder", "NewEncoder", "CorruptInputError"}, 141 | "encoding/asn1": {"Marshal", "MarshalWithParams", "Unmarshal", "UnmarshalWithParams", "BitString", "Enumerated", "Flag", "ObjectIdentifier", "RawContent", "RawValue", "StructuralError", "SyntaxError"}, 142 | "encoding/base32": {"NewDecoder", "NewEncoder", "CorruptInputError", "Encoding", "NewEncoding"}, 143 | "encoding/base64": {"NewDecoder", "NewEncoder", "CorruptInputError", "Encoding", "NewEncoding"}, 144 | "encoding/binary": {"AppendUvarint", "AppendVarint", "PutUvarint", "PutVarint", "Read", "ReadUvarint", "ReadVarint", "Size", "Uvarint", "Varint", "Write", "AppendByteOrder", "ByteOrder"}, 145 | "encoding/csv": {"ParseError", "Reader", "NewReader", "Writer", "NewWriter"}, 146 | "encoding/gob": {"Register", "RegisterName", "CommonType", "Decoder", "NewDecoder", "Encoder", "NewEncoder", "GobDecoder", "GobEncoder"}, 147 | "encoding/hex": {"AppendDecode", "AppendEncode", "Decode", "DecodeString", "DecodedLen", "Dump", "Dumper", "Encode", "EncodeToString", "EncodedLen", "NewDecoder", "NewEncoder", "InvalidByteError"}, 148 | "encoding/json": {"Compact", "HTMLEscape", "Indent", "Marshal", "MarshalIndent", "Unmarshal", "Valid", "Decoder", "NewDecoder", "Delim", "Encoder", "NewEncoder", "InvalidUTF8Error", "InvalidUnmarshalError", "Marshaler", "MarshalerError", "Number", "RawMessage", "SyntaxError", "Token", "UnmarshalFieldError", "UnmarshalTypeError", "Unmarshaler", "UnsupportedTypeError", "UnsupportedValueError"}, 149 | "encoding/pem": {"Encode", "EncodeToMemory", "Block", "Decode"}, 150 | "encoding/xml": {"Escape", "EscapeText", "Marshal", "MarshalIndent", "Unmarshal", "Attr", "CharData", "Comment", "Decoder", "NewDecoder", "NewTokenDecoder", "Directive", "Encoder", "NewEncoder", "EndElement", "Marshaler", "MarshalerAttr", "Name", "ProcInst", "StartElement", "SyntaxError", "TagPathError", "Token", "CopyToken", "TokenReader", "UnmarshalError", "Unmarshaler", "UnmarshalerAttr", "UnsupportedTypeError"}, 151 | "errors": {"As", "Is", "Join", "New", "Unwrap"}, 152 | "expvar": {"Do", "Handler", "Publish", "Float", "NewFloat", "Func", "Int", "NewInt", "KeyValue", "Map", "NewMap", "String", "NewString", "Var", "Get"}, 153 | "flag": {"Arg", "Args", "Bool", "BoolFunc", "BoolVar", "Duration", "DurationVar", "Float64", "Float64Var", "Func", "Int", "Int64", "Int64Var", "IntVar", "NArg", "NFlag", "Parse", "Parsed", "PrintDefaults", "Set", "String", "StringVar", "TextVar", "Uint", "Uint64", "Uint64Var", "UintVar", "UnquoteUsage", "Var", "Visit", "VisitAll", "ErrorHandling", "Flag", "Lookup", "FlagSet", "NewFlagSet", "Getter", "Value"}, 154 | "fmt": {"Append", "Appendf", "Appendln", "Errorf", "FormatString", "Fprint", "Fprintf", "Fprintln", "Fscan", "Fscanf", "Fscanln", "Print", "Printf", "Println", "Scan", "Scanf", "Scanln", "Sprint", "Sprintf", "Sprintln", "Sscan", "Sscanf", "Sscanln", "Formatter", "GoStringer", "ScanState", "Scanner", "State", "Stringer"}, 155 | "go/ast": {"FileExports", "FilterDecl", "FilterFile", "FilterPackage", "Fprint", "Inspect", "IsExported", "IsGenerated", "NotNilFilter", "PackageExports", "Print", "SortImports", "Walk", "ArrayType", "AssignStmt", "BadDecl", "BadExpr", "BadStmt", "BasicLit", "BinaryExpr", "BlockStmt", "BranchStmt", "CallExpr", "CaseClause", "ChanDir", "ChanType", "CommClause", "Comment", "CommentGroup", "CommentMap", "NewCommentMap", "CompositeLit", "Decl", "DeclStmt", "DeferStmt", "Ellipsis", "EmptyStmt", "Expr", "Unparen", "ExprStmt", "Field", "FieldFilter", "FieldList", "File", "MergePackageFiles", "Filter", "ForStmt", "FuncDecl", "FuncLit", "FuncType", "GenDecl", "GoStmt", "Ident", "NewIdent", "IfStmt", "ImportSpec", "Importer", "IncDecStmt", "IndexExpr", "IndexListExpr", "InterfaceType", "KeyValueExpr", "LabeledStmt", "MapType", "MergeMode", "Node", "ObjKind", "Object", "NewObj", "Package", "NewPackage", "ParenExpr", "RangeStmt", "ReturnStmt", "Scope", "NewScope", "SelectStmt", "SelectorExpr", "SendStmt", "SliceExpr", "Spec", "StarExpr", "Stmt", "StructType", "SwitchStmt", "TypeAssertExpr", "TypeSpec", "TypeSwitchStmt", "UnaryExpr", "ValueSpec", "Visitor"}, 156 | "go/build": {"ArchChar", "IsLocalImport", "Context", "Directive", "ImportMode", "MultiplePackageError", "NoGoError", "Package", "Import", "ImportDir"}, 157 | "go/build/constraint": {"GoVersion", "IsGoBuild", "IsPlusBuild", "PlusBuildLines", "AndExpr", "Expr", "Parse", "NotExpr", "OrExpr", "SyntaxError", "TagExpr"}, 158 | "go/constant": {"BitLen", "BoolVal", "Bytes", "Compare", "Float32Val", "Float64Val", "Int64Val", "Sign", "StringVal", "Uint64Val", "Val", "Kind", "Value", "BinaryOp", "Denom", "Imag", "Make", "MakeBool", "MakeFloat64", "MakeFromBytes", "MakeFromLiteral", "MakeImag", "MakeInt64", "MakeString", "MakeUint64", "MakeUnknown", "Num", "Real", "Shift", "ToComplex", "ToFloat", "ToInt", "UnaryOp"}, 159 | "go/doc": {"IsPredeclared", "Synopsis", "ToHTML", "ToText", "Example", "Examples", "Filter", "Func", "Mode", "Note", "Package", "New", "NewFromFiles", "Type", "Value"}, 160 | "go/doc/comment": {"DefaultLookupPackage", "Block", "Code", "Doc", "DocLink", "Heading", "Italic", "Link", "LinkDef", "List", "ListItem", "Paragraph", "Parser", "Plain", "Printer", "Text"}, 161 | "go/format": {"Node", "Source"}, 162 | "go/importer": {"Default", "For", "ForCompiler", "Lookup"}, 163 | "go/internal/gccgoimporter": {"GccgoInstallation", "Importer", "GetImporter", "InitData", "PackageInit"}, 164 | "go/internal/gcimporter": {"FindExportData", "FindPkg", "Import"}, 165 | "go/internal/srcimporter": {"Importer", "New"}, 166 | "go/internal/typeparams": {"PackIndexExpr", "IndexExpr", "UnpackIndexExpr"}, 167 | "go/parser": {"ParseDir", "ParseExpr", "ParseExprFrom", "ParseFile", "Mode"}, 168 | "go/printer": {"Fprint", "CommentedNode", "Config", "Mode"}, 169 | "go/scanner": {"PrintError", "Error", "ErrorHandler", "ErrorList", "Mode", "Scanner"}, 170 | "go/token": {"IsExported", "IsIdentifier", "IsKeyword", "File", "FileSet", "NewFileSet", "Pos", "Position", "Token", "Lookup"}, 171 | "go/types": {"AssertableTo", "AssignableTo", "CheckExpr", "Comparable", "ConvertibleTo", "DefPredeclaredTestFuncs", "ExprString", "Id", "Identical", "IdenticalIgnoreTags", "Implements", "IsInterface", "ObjectString", "Satisfies", "SelectionString", "TypeString", "WriteExpr", "WriteSignature", "WriteType", "Alias", "NewAlias", "ArgumentError", "Array", "NewArray", "Basic", "BasicInfo", "BasicKind", "Builtin", "Chan", "NewChan", "ChanDir", "Checker", "NewChecker", "Config", "Const", "NewConst", "Context", "NewContext", "Error", "Func", "MissingMethod", "NewFunc", "ImportMode", "Importer", "ImporterFrom", "Info", "Initializer", "Instance", "Interface", "NewInterface", "NewInterfaceType", "Label", "NewLabel", "Map", "NewMap", "MethodSet", "NewMethodSet", "Named", "NewNamed", "Nil", "Object", "LookupFieldOrMethod", "Package", "NewPackage", "PkgName", "NewPkgName", "Pointer", "NewPointer", "Qualifier", "RelativeTo", "Scope", "NewScope", "Selection", "SelectionKind", "Signature", "NewSignature", "NewSignatureType", "Sizes", "SizesFor", "Slice", "NewSlice", "StdSizes", "Struct", "NewStruct", "Term", "NewTerm", "Tuple", "NewTuple", "Type", "Default", "Instantiate", "Unalias", "TypeAndValue", "Eval", "TypeList", "TypeName", "NewTypeName", "TypeParam", "NewTypeParam", "TypeParamList", "Union", "NewUnion", "Var", "NewField", "NewParam", "NewVar"}, 172 | "go/version": {"Compare", "IsValid", "Lang"}, 173 | "hash": {"Hash", "Hash32", "Hash64"}, 174 | "hash/adler32": {"Checksum", "New"}, 175 | "hash/crc32": {"Checksum", "ChecksumIEEE", "New", "NewIEEE", "Update", "Table", "MakeTable"}, 176 | "hash/crc64": {"Checksum", "New", "Update", "Table", "MakeTable"}, 177 | "hash/fnv": {"New128", "New128a", "New32", "New32a", "New64", "New64a"}, 178 | "hash/maphash": {"Bytes", "String", "Hash", "Seed", "MakeSeed"}, 179 | "html": {"EscapeString", "UnescapeString"}, 180 | "html/template": {"HTMLEscape", "HTMLEscapeString", "HTMLEscaper", "IsTrue", "JSEscape", "JSEscapeString", "JSEscaper", "URLQueryEscaper", "CSS", "Error", "ErrorCode", "FuncMap", "HTML", "HTMLAttr", "JS", "JSStr", "Srcset", "Template", "Must", "New", "ParseFS", "ParseFiles", "ParseGlob", "URL"}, 181 | "image": {"RegisterFormat", "Alpha", "NewAlpha", "Alpha16", "NewAlpha16", "CMYK", "NewCMYK", "Config", "DecodeConfig", "Gray", "NewGray", "Gray16", "NewGray16", "Image", "Decode", "NRGBA", "NewNRGBA", "NRGBA64", "NewNRGBA64", "NYCbCrA", "NewNYCbCrA", "Paletted", "NewPaletted", "PalettedImage", "Point", "Pt", "RGBA", "NewRGBA", "RGBA64", "NewRGBA64", "RGBA64Image", "Rectangle", "Rect", "Uniform", "NewUniform", "YCbCr", "NewYCbCr", "YCbCrSubsampleRatio"}, 182 | "image/color": {"CMYKToRGB", "RGBToCMYK", "RGBToYCbCr", "YCbCrToRGB", "Alpha", "Alpha16", "CMYK", "Color", "Gray", "Gray16", "Model", "ModelFunc", "NRGBA", "NRGBA64", "NYCbCrA", "Palette", "RGBA", "RGBA64", "YCbCr"}, 183 | "image/color/palette": {}, 184 | "image/draw": {"Draw", "DrawMask", "Drawer", "Image", "Op", "Quantizer", "RGBA64Image"}, 185 | "image/gif": {"Decode", "DecodeConfig", "Encode", "EncodeAll", "GIF", "DecodeAll", "Options"}, 186 | "image/internal/imageutil": {"DrawYCbCr"}, 187 | "image/jpeg": {"Decode", "DecodeConfig", "Encode", "FormatError", "Options", "Reader", "UnsupportedError"}, 188 | "image/png": {"Decode", "DecodeConfig", "Encode", "CompressionLevel", "Encoder", "EncoderBuffer", "EncoderBufferPool", "FormatError", "UnsupportedError"}, 189 | "index/suffixarray": {"Index", "New"}, 190 | "internal/abi": {"CommonSize", "FuncPCABI0", "FuncPCABIInternal", "StructFieldSize", "TFlagOff", "UncommonSize", "UseInterfaceSwitchCache", "ArrayType", "ChanDir", "ChanType", "FuncFlag", "FuncID", "FuncType", "Imethod", "IntArgRegBitmap", "InterfaceSwitch", "InterfaceSwitchCache", "InterfaceSwitchCacheEntry", "InterfaceType", "Kind", "MapType", "Method", "Name", "NewName", "NameOff", "PtrType", "RegArgs", "SliceType", "StructField", "StructType", "TFlag", "TextOff", "Type", "TypeAssert", "TypeAssertCache", "TypeAssertCacheEntry", "TypeOff", "UncommonType"}, 191 | "internal/bisect": {"AppendMarker", "CutMarker", "Hash", "Marker", "PrintMarker", "Matcher", "New", "Writer"}, 192 | "internal/buildcfg": {"Check", "GOGOARCH", "Getgoextlinkenabled", "ExperimentFlags", "ParseGOEXPERIMENT"}, 193 | "internal/bytealg": {"Compare", "Count", "CountString", "Cutover", "Equal", "HashStr", "HashStrRev", "Index", "IndexByte", "IndexByteString", "IndexRabinKarp", "IndexString", "LastIndexByte", "LastIndexByteString", "LastIndexRabinKarp", "MakeNoZero"}, 194 | "internal/cfg": {}, 195 | "internal/chacha8rand": {"Marshal", "Unmarshal", "State"}, 196 | "internal/coverage": {"HardCodedPkgID", "Round4", "CounterFileFooter", "CounterFileHeader", "CounterFlavor", "CounterGranularity", "CounterMode", "ParseCounterMode", "CounterSegmentHeader", "CoverableUnit", "FuncDesc", "MetaFileCollection", "MetaFileHeader", "MetaSymbolHeader"}, 197 | "internal/coverage/calloc": {"BatchCounterAlloc"}, 198 | "internal/coverage/cformat": {"Formatter", "NewFormatter"}, 199 | "internal/coverage/cmerge": {"SaturatingAdd", "Merger", "ModeMergePolicy"}, 200 | "internal/coverage/decodecounter": {"CounterDataReader", "NewCounterDataReader", "FuncPayload"}, 201 | "internal/coverage/decodemeta": {"CoverageMetaDataDecoder", "NewCoverageMetaDataDecoder", "CoverageMetaFileReader", "NewCoverageMetaFileReader"}, 202 | "internal/coverage/encodecounter": {"CounterVisitor", "CounterVisitorFn", "CoverageDataWriter", "NewCoverageDataWriter"}, 203 | "internal/coverage/encodemeta": {"HashFuncDesc", "CoverageMetaDataBuilder", "NewCoverageMetaDataBuilder", "CoverageMetaFileWriter", "NewCoverageMetaFileWriter"}, 204 | "internal/coverage/pods": {"Pod", "CollectPods", "CollectPodsFromFiles"}, 205 | "internal/coverage/rtcov": {"CovCounterBlob", "CovMetaBlob"}, 206 | "internal/coverage/slicereader": {"Reader", "NewReader"}, 207 | "internal/coverage/slicewriter": {"WriteSeeker"}, 208 | "internal/coverage/stringtab": {"Reader", "NewReader", "Writer"}, 209 | "internal/coverage/uleb128": {"AppendUleb128"}, 210 | "internal/cpu": {"Initialize", "Name", "CacheLinePad"}, 211 | "internal/dag": {"Graph", "Parse"}, 212 | "internal/diff": {"Diff"}, 213 | "internal/fmtsort": {"SortedMap", "Sort"}, 214 | "internal/fuzz": {"CheckCorpus", "CoordinateFuzzing", "ResetCoverage", "RunFuzzWorker", "SnapshotCoverage", "CoordinateFuzzingOpts", "CorpusEntry", "ReadCorpus", "MalformedCorpusError"}, 215 | "internal/goarch": {"ArchFamilyType"}, 216 | "internal/godebug": {"Setting", "New"}, 217 | "internal/godebugs": {"Info", "Lookup"}, 218 | "internal/goexperiment": {"Flags"}, 219 | "internal/goos": {}, 220 | "internal/goroot": {"IsStandardPackage"}, 221 | "internal/gover": {"CmpInt", "Compare", "DecInt", "IsLang", "IsValid", "Lang", "Max", "Version", "Parse"}, 222 | "internal/goversion": {}, 223 | "internal/intern": {"Value", "Get", "GetByString"}, 224 | "internal/itoa": {"Itoa", "Uitoa", "Uitox"}, 225 | "internal/lazyregexp": {"Regexp", "New"}, 226 | "internal/lazytemplate": {"Template", "New"}, 227 | "internal/nettrace": {"LookupIPAltResolverKey", "Trace", "TraceKey"}, 228 | "internal/obscuretestdata": {"DecodeToTempFile", "ReadFile", "Rot13"}, 229 | "internal/oserror": {}, 230 | "internal/pkgbits": {"Code", "CodeObj", "CodeType", "CodeVal", "Decoder", "Encoder", "Index", "PkgDecoder", "NewPkgDecoder", "PkgEncoder", "NewPkgEncoder", "RelocEnt", "RelocKind", "SyncMarker"}, 231 | "internal/platform": {"ASanSupported", "Broken", "BuildModeSupported", "CgoSupported", "DefaultPIE", "ExecutableHasDWARF", "FirstClass", "FuzzInstrumented", "FuzzSupported", "InternalLinkPIESupported", "MSanSupported", "MustLinkExternal", "RaceDetectorSupported", "OSArch"}, 232 | "internal/poll": {"CopyFileRange", "DupCloseOnExec", "IsPollDescriptor", "SendFile", "Splice", "DeadlineExceededError", "FD", "String", "SysFile"}, 233 | "internal/profile": {"Demangler", "Function", "Label", "Line", "Location", "Mapping", "Profile", "Merge", "Parse", "ParseTracebacks", "Sample", "TagMatch", "ValueType"}, 234 | "internal/race": {"Acquire", "Disable", "Enable", "Errors", "Read", "ReadRange", "Release", "ReleaseMerge", "Write", "WriteRange"}, 235 | "internal/reflectlite": {"Swapper", "Kind", "Type", "TypeOf", "Value", "ValueOf", "ValueError"}, 236 | "internal/safefilepath": {"FromFS"}, 237 | "internal/saferio": {"ReadData", "ReadDataAt", "SliceCap", "SliceCapWithSize"}, 238 | "internal/singleflight": {"Group", "Result"}, 239 | "internal/syscall/execenv": {"Default"}, 240 | "internal/syscall/unix": {"CopyFileRange", "Eaccess", "Fcntl", "Fstatat", "GetRandom", "HasNonblockFlag", "IsNonblock", "KernelVersion", "Openat", "PidFDSendSignal", "RecvfromInet4", "RecvfromInet6", "RecvmsgInet4", "RecvmsgInet6", "SendmsgNInet4", "SendmsgNInet6", "SendtoInet4", "SendtoInet6", "Unlinkat", "GetRandomFlag"}, 241 | "internal/syscall/windows": {"AdjustTokenPrivileges", "CreateEnvironmentBlock", "CreateEvent", "DestroyEnvironmentBlock", "DuplicateTokenEx", "ErrorLoadingGetTempPath2", "GetACP", "GetAdaptersAddresses", "GetComputerNameEx", "GetConsoleCP", "GetCurrentThread", "GetFileInformationByHandleEx", "GetFinalPathNameByHandle", "GetModuleFileName", "GetProcessMemoryInfo", "GetProfilesDirectory", "GetSystemDirectory", "GetTempPath2", "GetVolumeInformationByHandle", "GetVolumeNameForVolumeMountPoint", "ImpersonateSelf", "LockFileEx", "LookupPrivilegeValue", "Module32First", "Module32Next", "MoveFileEx", "MultiByteToWideChar", "NetShareAdd", "NetShareDel", "NetUserGetLocalGroups", "OpenSCManager", "OpenService", "OpenThreadToken", "ProcessPrng", "QueryServiceStatus", "Rename", "RevertToSelf", "RtlLookupFunctionEntry", "RtlVirtualUnwind", "SetFileInformationByHandle", "SetTokenInformation", "UTF16PtrToString", "UnlockFileEx", "VirtualQuery", "WSARecvMsg", "WSASendMsg", "WSASendtoInet4", "WSASendtoInet6", "WSASocket", "FILE_ATTRIBUTE_TAG_INFO", "FILE_BASIC_INFO", "FILE_FULL_DIR_INFO", "FILE_ID_BOTH_DIR_INFO", "IpAdapterAddresses", "IpAdapterAnycastAddress", "IpAdapterDnsServerAdapter", "IpAdapterMulticastAddress", "IpAdapterPrefix", "IpAdapterUnicastAddress", "LUID", "LUID_AND_ATTRIBUTES", "LocalGroupUserInfo0", "MemoryBasicInformation", "ModuleEntry32", "MountPointReparseBuffer", "PROCESS_MEMORY_COUNTERS", "REPARSE_DATA_BUFFER", "REPARSE_DATA_BUFFER_HEADER", "SERVICE_STATUS", "SHARE_INFO_2", "SID_AND_ATTRIBUTES", "SecurityAttributes", "SocketAddress", "SymbolicLinkReparseBuffer", "TCP_INITIAL_RTO_PARAMETERS", "TOKEN_MANDATORY_LABEL", "TOKEN_PRIVILEGES", "TokenType", "UserInfo4", "WSAMsg"}, 242 | "internal/syscall/windows/registry": {"DeleteKey", "ExpandString", "Key", "CreateKey", "OpenKey", "KeyInfo"}, 243 | "internal/syscall/windows/sysdll": {"Add"}, 244 | "internal/sysinfo": {"CPUName"}, 245 | "internal/testenv": {"Builder", "CPUIsSlow", "CanInternalLink", "CleanCmdEnv", "Command", "CommandContext", "GOROOT", "GoTool", "GoToolPath", "HasCGO", "HasExternalNetwork", "HasGoBuild", "HasGoRun", "HasLink", "HasParallelism", "HasSrc", "HasSymlink", "MustHaveBuildMode", "MustHaveCGO", "MustHaveExec", "MustHaveExecPath", "MustHaveExternalNetwork", "MustHaveGoBuild", "MustHaveGoRun", "MustHaveLink", "MustHaveParallelism", "MustHaveSymlink", "MustInternalLink", "OptimizationOff", "SkipFlaky", "SkipFlakyNet", "SkipIfOptimizationOff", "SkipIfShortAndSlow", "SyscallIsNotSupported", "WriteImportcfg"}, 246 | "internal/testlog": {"Getenv", "Open", "PanicOnExit0", "SetLogger", "SetPanicOnExit0", "Stat", "Interface", "Logger"}, 247 | "internal/testpty": {"Open", "PtyError"}, 248 | "internal/trace": {"GoroutineStats", "IsSystemGoroutine", "MutatorUtilization", "MutatorUtilizationV2", "Print", "PrintEvent", "ReadVersion", "RelatedGoroutines", "RelatedGoroutinesV2", "Event", "Frame", "GDesc", "GExecutionStat", "GoroutineExecStats", "GoroutineSummary", "MMUCurve", "NewMMUCurve", "MutatorUtil", "ParseResult", "Parse", "Summarizer", "NewSummarizer", "Summary", "UserRegionDesc", "UserRegionSummary", "UserTaskSummary", "UtilFlags", "UtilWindow", "Writer", "NewWriter"}, 249 | "internal/trace/traceviewer": {"BuildProfile", "MMUHandlerFunc", "MainHandler", "SVGProfileHandlerFunc", "StaticHandler", "TraceHandler", "WalkStackFrames", "ArrowEvent", "AsyncSliceEvent", "Emitter", "NewEmitter", "GState", "InstantEvent", "Mode", "MutatorUtilFunc", "ProfileFunc", "ProfileRecord", "Range", "SliceEvent", "ThreadState", "TimeHistogram", "TraceConsumer", "SplittingTraceConsumer", "ViewerDataTraceConsumer", "View", "ViewType"}, 250 | "internal/trace/traceviewer/format": {"BlockedArg", "Data", "Event", "Frame", "GoroutineCountersArg", "HeapCountersArg", "NameArg", "SortIndexArg", "ThreadCountersArg", "ThreadIDArg"}, 251 | "internal/trace/v2": {"Event", "EventKind", "GoID", "GoState", "Label", "Log", "Metric", "ProcID", "ProcState", "Range", "RangeAttribute", "Reader", "NewReader", "Region", "ResourceID", "MakeResourceID", "ResourceKind", "Stack", "StackFrame", "StateTransition", "Task", "TaskID", "ThreadID", "Time", "Value", "ValueKind"}, 252 | "internal/trace/v2/event": {"Names", "Constraint", "SchedReqs", "Spec", "Type"}, 253 | "internal/trace/v2/event/go122": {"EventString", "Specs", "GoStatus", "ProcStatus"}, 254 | "internal/trace/v2/internal/testgen/go122": {"Main", "Batch", "Generation", "Seq", "Time", "Trace", "NewTrace"}, 255 | "internal/trace/v2/raw": {"Event", "Reader", "NewReader", "TextReader", "NewTextReader", "TextWriter", "NewTextWriter", "Writer", "NewWriter"}, 256 | "internal/trace/v2/testtrace": {"Expectation", "ExpectSuccess", "ParseExpectation", "ParseFile", "Validator", "NewValidator"}, 257 | "internal/trace/v2/version": {"WriteHeader", "Version", "ReadHeader"}, 258 | "internal/txtar": {"Format", "Archive", "Parse", "ParseFile", "File"}, 259 | "internal/types/errors": {"Code"}, 260 | "internal/unsafeheader": {"Slice", "String"}, 261 | "internal/xcoff": {"Archive", "NewArchive", "OpenArchive", "ArchiveHeader", "AuxCSect32", "AuxCSect64", "AuxFcn32", "AuxFcn64", "AuxFile64", "AuxSect64", "AuxiliaryCSect", "AuxiliaryFcn", "File", "NewFile", "Open", "FileHeader", "FileHeader32", "FileHeader64", "ImportedSymbol", "LoaderHeader32", "LoaderHeader64", "LoaderSymbol32", "LoaderSymbol64", "Member", "MemberHeader", "Reloc", "Reloc32", "Reloc64", "Section", "SectionHeader", "SectionHeader32", "SectionHeader64", "SymEnt32", "SymEnt64", "Symbol"}, 262 | "internal/zstd": {"Reader", "NewReader"}, 263 | "io": {"Copy", "CopyBuffer", "CopyN", "Pipe", "ReadAll", "ReadAtLeast", "ReadFull", "WriteString", "ByteReader", "ByteScanner", "ByteWriter", "Closer", "LimitedReader", "OffsetWriter", "NewOffsetWriter", "PipeReader", "PipeWriter", "ReadCloser", "NopCloser", "ReadSeekCloser", "ReadSeeker", "ReadWriteCloser", "ReadWriteSeeker", "ReadWriter", "Reader", "LimitReader", "MultiReader", "TeeReader", "ReaderAt", "ReaderFrom", "RuneReader", "RuneScanner", "SectionReader", "NewSectionReader", "Seeker", "StringWriter", "WriteCloser", "WriteSeeker", "Writer", "MultiWriter", "WriterAt", "WriterTo"}, 264 | "io/fs": {"FormatDirEntry", "FormatFileInfo", "Glob", "ReadFile", "ValidPath", "WalkDir", "DirEntry", "FileInfoToDirEntry", "ReadDir", "FS", "Sub", "File", "FileInfo", "Stat", "FileMode", "GlobFS", "PathError", "ReadDirFS", "ReadDirFile", "ReadFileFS", "StatFS", "SubFS", "WalkDirFunc"}, 265 | "io/ioutil": {"NopCloser", "ReadAll", "ReadDir", "ReadFile", "TempDir", "TempFile", "WriteFile"}, 266 | "log": {"Fatal", "Fatalf", "Fatalln", "Flags", "Output", "Panic", "Panicf", "Panicln", "Prefix", "Print", "Printf", "Println", "SetFlags", "SetOutput", "SetPrefix", "Writer", "Logger", "Default", "New"}, 267 | "log/internal": {}, 268 | "log/slog": {"Debug", "DebugContext", "Error", "ErrorContext", "Info", "InfoContext", "Log", "LogAttrs", "NewLogLogger", "SetDefault", "Warn", "WarnContext", "Attr", "Any", "Bool", "Duration", "Float64", "Group", "Int", "Int64", "String", "Time", "Uint64", "Handler", "HandlerOptions", "JSONHandler", "NewJSONHandler", "Kind", "Level", "SetLogLoggerLevel", "LevelVar", "Leveler", "LogValuer", "Logger", "Default", "New", "With", "Record", "NewRecord", "Source", "TextHandler", "NewTextHandler", "Value", "AnyValue", "BoolValue", "DurationValue", "Float64Value", "GroupValue", "Int64Value", "IntValue", "StringValue", "TimeValue", "Uint64Value"}, 269 | "log/slog/internal": {}, 270 | "log/slog/internal/benchmarks": {}, 271 | "log/slog/internal/buffer": {"Buffer", "New"}, 272 | "log/slog/internal/slogtest": {"RemoveTime"}, 273 | "log/syslog": {"NewLogger", "Priority", "Writer", "Dial", "New"}, 274 | "maps": {"Clone", "Copy", "DeleteFunc", "Equal", "EqualFunc"}, 275 | "math": {"Abs", "Acos", "Acosh", "Asin", "Asinh", "Atan", "Atan2", "Atanh", "Cbrt", "Ceil", "Copysign", "Cos", "Cosh", "Dim", "Erf", "Erfc", "Erfcinv", "Erfinv", "Exp", "Exp2", "Expm1", "FMA", "Float32bits", "Float32frombits", "Float64bits", "Float64frombits", "Floor", "Frexp", "Gamma", "Hypot", "Ilogb", "Inf", "IsInf", "IsNaN", "J0", "J1", "Jn", "Ldexp", "Lgamma", "Log", "Log10", "Log1p", "Log2", "Logb", "Max", "Min", "Mod", "Modf", "NaN", "Nextafter", "Nextafter32", "Pow", "Pow10", "Remainder", "Round", "RoundToEven", "Signbit", "Sin", "Sincos", "Sinh", "Sqrt", "Tan", "Tanh", "Trunc", "Y0", "Y1", "Yn"}, 276 | "math/big": {"Jacobi", "Accuracy", "ErrNaN", "Float", "NewFloat", "ParseFloat", "Int", "NewInt", "Rat", "NewRat", "RoundingMode", "Word"}, 277 | "math/bits": {"Add", "Add32", "Add64", "Div", "Div32", "Div64", "LeadingZeros", "LeadingZeros16", "LeadingZeros32", "LeadingZeros64", "LeadingZeros8", "Len", "Len16", "Len32", "Len64", "Len8", "Mul", "Mul32", "Mul64", "OnesCount", "OnesCount16", "OnesCount32", "OnesCount64", "OnesCount8", "Rem", "Rem32", "Rem64", "Reverse", "Reverse16", "Reverse32", "Reverse64", "Reverse8", "ReverseBytes", "ReverseBytes16", "ReverseBytes32", "ReverseBytes64", "RotateLeft", "RotateLeft16", "RotateLeft32", "RotateLeft64", "RotateLeft8", "Sub", "Sub32", "Sub64", "TrailingZeros", "TrailingZeros16", "TrailingZeros32", "TrailingZeros64", "TrailingZeros8"}, 278 | "math/cmplx": {"Abs", "Acos", "Acosh", "Asin", "Asinh", "Atan", "Atanh", "Conj", "Cos", "Cosh", "Cot", "Exp", "Inf", "IsInf", "IsNaN", "Log", "Log10", "NaN", "Phase", "Polar", "Pow", "Rect", "Sin", "Sinh", "Sqrt", "Tan", "Tanh"}, 279 | "math/rand": {"ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", "NormFloat64", "Perm", "Read", "Seed", "Shuffle", "Uint32", "Uint64", "Rand", "New", "Source", "NewSource", "Source64", "Zipf", "NewZipf"}, 280 | "math/rand/v2": {"ExpFloat64", "Float32", "Float64", "Int", "Int32", "Int32N", "Int64", "Int64N", "IntN", "N", "NormFloat64", "Perm", "Shuffle", "Uint32", "Uint32N", "Uint64", "Uint64N", "UintN", "ChaCha8", "NewChaCha8", "PCG", "NewPCG", "Rand", "New", "Source", "Zipf", "NewZipf"}, 281 | "mime": {"AddExtensionType", "ExtensionsByType", "FormatMediaType", "ParseMediaType", "TypeByExtension", "WordDecoder", "WordEncoder"}, 282 | "mime/multipart": {"File", "FileHeader", "Form", "Part", "Reader", "NewReader", "Writer", "NewWriter"}, 283 | "mime/quotedprintable": {"Reader", "NewReader", "Writer", "NewWriter"}, 284 | "net": {"JoinHostPort", "LookupAddr", "LookupCNAME", "LookupHost", "LookupPort", "LookupTXT", "ParseCIDR", "Pipe", "SplitHostPort", "Addr", "InterfaceAddrs", "AddrError", "Buffers", "Conn", "Dial", "DialTimeout", "FileConn", "DNSConfigError", "DNSError", "Dialer", "Error", "Flags", "HardwareAddr", "ParseMAC", "IP", "IPv4", "LookupIP", "ParseIP", "IPAddr", "ResolveIPAddr", "IPConn", "DialIP", "ListenIP", "IPMask", "CIDRMask", "IPv4Mask", "IPNet", "Interface", "InterfaceByIndex", "InterfaceByName", "Interfaces", "InvalidAddrError", "ListenConfig", "Listener", "FileListener", "Listen", "MX", "LookupMX", "NS", "LookupNS", "OpError", "PacketConn", "FilePacketConn", "ListenPacket", "ParseError", "Resolver", "SRV", "LookupSRV", "TCPAddr", "ResolveTCPAddr", "TCPAddrFromAddrPort", "TCPConn", "DialTCP", "TCPListener", "ListenTCP", "UDPAddr", "ResolveUDPAddr", "UDPAddrFromAddrPort", "UDPConn", "DialUDP", "ListenMulticastUDP", "ListenUDP", "UnixAddr", "ResolveUnixAddr", "UnixConn", "DialUnix", "ListenUnixgram", "UnixListener", "ListenUnix", "UnknownNetworkError"}, 285 | "net/http": {"CanonicalHeaderKey", "DetectContentType", "Error", "Handle", "HandleFunc", "ListenAndServe", "ListenAndServeTLS", "MaxBytesReader", "NotFound", "ParseHTTPVersion", "ParseTime", "ProxyFromEnvironment", "ProxyURL", "Redirect", "Serve", "ServeContent", "ServeFile", "ServeFileFS", "ServeTLS", "SetCookie", "StatusText", "Client", "CloseNotifier", "ConnState", "Cookie", "CookieJar", "Dir", "File", "FileSystem", "FS", "Flusher", "Handler", "AllowQuerySemicolons", "FileServer", "FileServerFS", "MaxBytesHandler", "NotFoundHandler", "RedirectHandler", "StripPrefix", "TimeoutHandler", "HandlerFunc", "Header", "Hijacker", "MaxBytesError", "ProtocolError", "PushOptions", "Pusher", "Request", "NewRequest", "NewRequestWithContext", "ReadRequest", "Response", "Get", "Head", "Post", "PostForm", "ReadResponse", "ResponseController", "NewResponseController", "ResponseWriter", "RoundTripper", "NewFileTransport", "NewFileTransportFS", "SameSite", "ServeMux", "NewServeMux", "Server", "Transport"}, 286 | "net/http/cgi": {"Request", "RequestFromMap", "Serve", "Handler"}, 287 | "net/http/cookiejar": {"Jar", "New", "Options", "PublicSuffixList"}, 288 | "net/http/fcgi": {"ProcessEnv", "Serve"}, 289 | "net/http/httptest": {"NewRequest", "ResponseRecorder", "NewRecorder", "Server", "NewServer", "NewTLSServer", "NewUnstartedServer"}, 290 | "net/http/httptrace": {"WithClientTrace", "ClientTrace", "ContextClientTrace", "DNSDoneInfo", "DNSStartInfo", "GotConnInfo", "WroteRequestInfo"}, 291 | "net/http/httputil": {"DumpRequest", "DumpRequestOut", "DumpResponse", "NewChunkedReader", "NewChunkedWriter", "BufferPool", "ClientConn", "NewClientConn", "NewProxyClientConn", "ProxyRequest", "ReverseProxy", "NewSingleHostReverseProxy", "ServerConn", "NewServerConn"}, 292 | "net/http/internal": {"NewChunkedReader", "NewChunkedWriter", "FlushAfterChunkWriter"}, 293 | "net/http/internal/ascii": {"EqualFold", "Is", "IsPrint", "ToLower"}, 294 | "net/http/internal/testcert": {}, 295 | "net/http/pprof": {"Cmdline", "Handler", "Index", "Profile", "Symbol", "Trace"}, 296 | "net/internal/socktest": {"AfterFilter", "Cookie", "Filter", "FilterType", "Sockets", "Stat", "Status", "Switch"}, 297 | "net/mail": {"ParseDate", "Address", "ParseAddress", "ParseAddressList", "AddressParser", "Header", "Message", "ReadMessage"}, 298 | "net/netip": {"Addr", "AddrFrom16", "AddrFrom4", "AddrFromSlice", "IPv4Unspecified", "IPv6LinkLocalAllNodes", "IPv6LinkLocalAllRouters", "IPv6Loopback", "IPv6Unspecified", "MustParseAddr", "ParseAddr", "AddrPort", "AddrPortFrom", "MustParseAddrPort", "ParseAddrPort", "Prefix", "MustParsePrefix", "ParsePrefix", "PrefixFrom"}, 299 | "net/rpc": {"Accept", "HandleHTTP", "Register", "RegisterName", "ServeCodec", "ServeConn", "ServeRequest", "Call", "Client", "Dial", "DialHTTP", "DialHTTPPath", "NewClient", "NewClientWithCodec", "ClientCodec", "Request", "Response", "Server", "NewServer", "ServerCodec", "ServerError"}, 300 | "net/rpc/jsonrpc": {"Dial", "NewClient", "NewClientCodec", "NewServerCodec", "ServeConn"}, 301 | "net/smtp": {"SendMail", "Auth", "CRAMMD5Auth", "PlainAuth", "Client", "Dial", "NewClient", "ServerInfo"}, 302 | "net/textproto": {"CanonicalMIMEHeaderKey", "TrimBytes", "TrimString", "Conn", "Dial", "NewConn", "Error", "MIMEHeader", "Pipeline", "ProtocolError", "Reader", "NewReader", "Writer", "NewWriter"}, 303 | "net/url": {"JoinPath", "PathEscape", "PathUnescape", "QueryEscape", "QueryUnescape", "Error", "EscapeError", "InvalidHostError", "URL", "Parse", "ParseRequestURI", "Userinfo", "User", "UserPassword", "Values", "ParseQuery"}, 304 | "os": {"Chdir", "Chmod", "Chown", "Chtimes", "Clearenv", "DirFS", "Environ", "Executable", "Exit", "Expand", "ExpandEnv", "Getegid", "Getenv", "Geteuid", "Getgid", "Getgroups", "Getpagesize", "Getpid", "Getppid", "Getuid", "Getwd", "Hostname", "IsExist", "IsNotExist", "IsPathSeparator", "IsPermission", "IsTimeout", "Lchown", "Link", "LookupEnv", "Mkdir", "MkdirAll", "MkdirTemp", "NewSyscallError", "Pipe", "ReadFile", "Readlink", "Remove", "RemoveAll", "Rename", "SameFile", "Setenv", "Symlink", "TempDir", "Truncate", "Unsetenv", "UserCacheDir", "UserConfigDir", "UserHomeDir", "WriteFile", "DirEntry", "ReadDir", "File", "Create", "CreateTemp", "NewFile", "Open", "OpenFile", "FileInfo", "Lstat", "Stat", "FileMode", "LinkError", "PathError", "ProcAttr", "Process", "FindProcess", "StartProcess", "ProcessState", "Signal", "SyscallError"}, 305 | "os/exec": {"LookPath", "Cmd", "Command", "CommandContext", "Error", "ExitError"}, 306 | "os/exec/internal/fdtest": {"Exists"}, 307 | "os/signal": {"Ignore", "Ignored", "Notify", "NotifyContext", "Reset", "Stop"}, 308 | "os/user": {"Group", "LookupGroup", "LookupGroupId", "UnknownGroupError", "UnknownGroupIdError", "UnknownUserError", "UnknownUserIdError", "User", "Current", "Lookup", "LookupId"}, 309 | "path": {"Base", "Clean", "Dir", "Ext", "IsAbs", "Join", "Match", "Split"}, 310 | "path/filepath": {"Abs", "Base", "Clean", "Dir", "EvalSymlinks", "Ext", "FromSlash", "Glob", "HasPrefix", "IsAbs", "IsLocal", "Join", "Match", "Rel", "Split", "SplitList", "ToSlash", "VolumeName", "Walk", "WalkDir", "WalkFunc"}, 311 | "plugin": {"Plugin", "Open", "Symbol"}, 312 | "reflect": {"Copy", "DeepEqual", "Swapper", "ChanDir", "Kind", "MapIter", "Method", "SelectCase", "SelectDir", "SliceHeader", "StringHeader", "StructField", "VisibleFields", "StructTag", "Type", "ArrayOf", "ChanOf", "FuncOf", "MapOf", "PointerTo", "PtrTo", "SliceOf", "StructOf", "TypeFor", "TypeOf", "Value", "Append", "AppendSlice", "Indirect", "MakeChan", "MakeFunc", "MakeMap", "MakeMapWithSize", "MakeSlice", "New", "NewAt", "Select", "ValueOf", "Zero", "ValueError"}, 313 | "reflect/internal/example1": {"MyStruct"}, 314 | "reflect/internal/example2": {"MyStruct"}, 315 | "regexp": {"Match", "MatchReader", "MatchString", "QuoteMeta", "Regexp", "Compile", "CompilePOSIX", "MustCompile", "MustCompilePOSIX"}, 316 | "regexp/syntax": {"IsWordChar", "EmptyOp", "EmptyOpContext", "Error", "ErrorCode", "Flags", "Inst", "InstOp", "Op", "Prog", "Compile", "Regexp", "Parse"}, 317 | "runtime": {"BlockProfile", "Breakpoint", "CPUProfile", "Caller", "Callers", "GC", "GOMAXPROCS", "GOROOT", "Goexit", "GoroutineProfile", "Gosched", "KeepAlive", "LockOSThread", "MemProfile", "MutexProfile", "NumCPU", "NumCgoCall", "NumGoroutine", "ReadMemStats", "ReadTrace", "SetBlockProfileRate", "SetCPUProfileRate", "SetCgoTraceback", "SetFinalizer", "SetMutexProfileFraction", "Stack", "StartTrace", "StopTrace", "ThreadCreateProfile", "UnlockOSThread", "Version", "BlockProfileRecord", "Error", "Frame", "Frames", "CallersFrames", "Func", "FuncForPC", "MemProfileRecord", "MemStats", "PanicNilError", "RuntimeError", "Pinner", "StackRecord", "TypeAssertionError"}, 318 | "runtime/cgo": {"Handle", "NewHandle", "Incomplete"}, 319 | "runtime/coverage": {"ClearCounters", "WriteCounters", "WriteCountersDir", "WriteMeta", "WriteMetaDir"}, 320 | "runtime/debug": {"FreeOSMemory", "PrintStack", "ReadGCStats", "SetGCPercent", "SetMaxStack", "SetMaxThreads", "SetMemoryLimit", "SetPanicOnFault", "SetTraceback", "Stack", "WriteHeapDump", "BuildInfo", "ParseBuildInfo", "ReadBuildInfo", "BuildSetting", "GCStats", "Module"}, 321 | "runtime/internal/atomic": {"And", "And32", "And64", "And8", "Anduintptr", "Cas", "Cas64", "CasRel", "Casint32", "Casint64", "Casp1", "Casuintptr", "Load", "Load64", "Load8", "LoadAcq", "LoadAcq64", "LoadAcquintptr", "Loadint32", "Loadint64", "Loadp", "Loaduint", "Loaduintptr", "Or", "Or32", "Or64", "Or8", "Oruintptr", "Store", "Store64", "Store8", "StoreRel", "StoreRel64", "StoreReluintptr", "Storeint32", "Storeint64", "StorepNoWB", "Storeuintptr", "Xadd", "Xadd64", "Xaddint32", "Xaddint64", "Xadduintptr", "Xchg", "Xchg64", "Xchgint32", "Xchgint64", "Xchguintptr", "Bool", "Float64", "Int32", "Int64", "Pointer", "Uint32", "Uint64", "Uint8", "Uintptr", "UnsafePointer"}, 322 | "runtime/internal/math": {"Add64", "Mul64", "MulUintptr"}, 323 | "runtime/internal/startlinetest": {"AsmFunc"}, 324 | "runtime/internal/sys": {"Bswap32", "Bswap64", "LeadingZeros64", "LeadingZeros8", "Len64", "Len8", "OnesCount64", "Prefetch", "PrefetchStreamed", "TrailingZeros32", "TrailingZeros64", "TrailingZeros8", "NotInHeap"}, 325 | "runtime/internal/syscall": {"EpollCreate1", "EpollCtl", "EpollWait", "Syscall6", "EpollEvent"}, 326 | "runtime/metrics": {"Read", "Description", "All", "Float64Histogram", "Sample", "Value", "ValueKind"}, 327 | "runtime/pprof": {"Do", "ForLabels", "Label", "SetGoroutineLabels", "StartCPUProfile", "StopCPUProfile", "WithLabels", "WriteHeapProfile", "LabelSet", "Labels", "Profile", "Lookup", "NewProfile", "Profiles"}, 328 | "runtime/race": {}, 329 | "runtime/race/internal/amd64v1": {}, 330 | "runtime/trace": {"IsEnabled", "Log", "Logf", "Start", "Stop", "WithRegion", "Region", "StartRegion", "Task", "NewTask"}, 331 | "slices": {"BinarySearch", "BinarySearchFunc", "Clip", "Clone", "Compact", "CompactFunc", "Compare", "CompareFunc", "Concat", "Contains", "ContainsFunc", "Delete", "DeleteFunc", "Equal", "EqualFunc", "Grow", "Index", "IndexFunc", "Insert", "IsSorted", "IsSortedFunc", "Max", "MaxFunc", "Min", "MinFunc", "Replace", "Reverse", "Sort", "SortFunc", "SortStableFunc"}, 332 | "sort": {"Find", "Float64s", "Float64sAreSorted", "Ints", "IntsAreSorted", "IsSorted", "Search", "SearchFloat64s", "SearchInts", "SearchStrings", "Slice", "SliceIsSorted", "SliceStable", "Sort", "Stable", "Strings", "StringsAreSorted", "Float64Slice", "IntSlice", "Interface", "Reverse", "StringSlice"}, 333 | "strconv": {"AppendBool", "AppendFloat", "AppendInt", "AppendQuote", "AppendQuoteRune", "AppendQuoteRuneToASCII", "AppendQuoteRuneToGraphic", "AppendQuoteToASCII", "AppendQuoteToGraphic", "AppendUint", "Atoi", "CanBackquote", "FormatBool", "FormatComplex", "FormatFloat", "FormatInt", "FormatUint", "IsGraphic", "IsPrint", "Itoa", "ParseBool", "ParseComplex", "ParseFloat", "ParseInt", "ParseUint", "Quote", "QuoteRune", "QuoteRuneToASCII", "QuoteRuneToGraphic", "QuoteToASCII", "QuoteToGraphic", "QuotedPrefix", "Unquote", "UnquoteChar", "NumError"}, 334 | "strings": {"Clone", "Compare", "Contains", "ContainsAny", "ContainsFunc", "ContainsRune", "Count", "Cut", "CutPrefix", "CutSuffix", "EqualFold", "Fields", "FieldsFunc", "HasPrefix", "HasSuffix", "Index", "IndexAny", "IndexByte", "IndexFunc", "IndexRune", "Join", "LastIndex", "LastIndexAny", "LastIndexByte", "LastIndexFunc", "Map", "Repeat", "Replace", "ReplaceAll", "Split", "SplitAfter", "SplitAfterN", "SplitN", "Title", "ToLower", "ToLowerSpecial", "ToTitle", "ToTitleSpecial", "ToUpper", "ToUpperSpecial", "ToValidUTF8", "Trim", "TrimFunc", "TrimLeft", "TrimLeftFunc", "TrimPrefix", "TrimRight", "TrimRightFunc", "TrimSpace", "TrimSuffix", "Builder", "Reader", "NewReader", "Replacer", "NewReplacer"}, 335 | "sync": {"OnceFunc", "OnceValue", "OnceValues", "Cond", "NewCond", "Locker", "Map", "Mutex", "Once", "Pool", "RWMutex", "WaitGroup"}, 336 | "sync/atomic": {"AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr", "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapPointer", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "LoadInt32", "LoadInt64", "LoadPointer", "LoadUint32", "LoadUint64", "LoadUintptr", "StoreInt32", "StoreInt64", "StorePointer", "StoreUint32", "StoreUint64", "StoreUintptr", "SwapInt32", "SwapInt64", "SwapPointer", "SwapUint32", "SwapUint64", "SwapUintptr", "Bool", "Int32", "Int64", "Pointer", "Uint32", "Uint64", "Uintptr", "Value"}, 337 | "syscall": {"Access", "Acct", "Adjtimex", "AttachLsf", "Bind", "BindToDevice", "BytePtrFromString", "ByteSliceFromString", "Chdir", "Chmod", "Chown", "Chroot", "Clearenv", "Close", "CloseOnExec", "CmsgLen", "CmsgSpace", "Connect", "Creat", "DetachLsf", "Dup", "Dup2", "Dup3", "Environ", "EpollCreate", "EpollCreate1", "EpollCtl", "EpollWait", "Exec", "Exit", "Faccessat", "Fallocate", "Fchdir", "Fchmod", "Fchmodat", "Fchown", "Fchownat", "FcntlFlock", "Fdatasync", "Flock", "ForkExec", "Fstat", "Fstatfs", "Fsync", "Ftruncate", "Futimes", "Futimesat", "Getcwd", "Getdents", "Getegid", "Getenv", "Geteuid", "Getgid", "Getgroups", "Getpagesize", "Getpgid", "Getpgrp", "Getpid", "Getppid", "Getpriority", "Getrlimit", "Getrusage", "GetsockoptInet4Addr", "GetsockoptInt", "Gettid", "Gettimeofday", "Getuid", "Getwd", "Getxattr", "InotifyAddWatch", "InotifyInit", "InotifyInit1", "InotifyRmWatch", "Ioperm", "Iopl", "Kill", "Klogctl", "Lchown", "Link", "Listen", "Listxattr", "LsfSocket", "Lstat", "Madvise", "Mkdir", "Mkdirat", "Mkfifo", "Mknod", "Mknodat", "Mlock", "Mlockall", "Mmap", "Mount", "Mprotect", "Munlock", "Munlockall", "Munmap", "Nanosleep", "NetlinkRIB", "Open", "Openat", "ParseDirent", "ParseUnixRights", "Pause", "Pipe", "Pipe2", "PivotRoot", "Pread", "PtraceAttach", "PtraceCont", "PtraceDetach", "PtraceGetEventMsg", "PtraceGetRegs", "PtracePeekData", "PtracePeekText", "PtracePokeData", "PtracePokeText", "PtraceSetOptions", "PtraceSetRegs", "PtraceSingleStep", "PtraceSyscall", "Pwrite", "Read", "ReadDirent", "Readlink", "Reboot", "Removexattr", "Rename", "Renameat", "Rmdir", "Seek", "Select", "Sendfile", "Sendmsg", "SendmsgN", "Sendto", "SetLsfPromisc", "SetNonblock", "Setdomainname", "Setegid", "Setenv", "Seteuid", "Setfsgid", "Setfsuid", "Setgid", "Setgroups", "Sethostname", "Setpgid", "Setpriority", "Setregid", "Setresgid", "Setresuid", "Setreuid", "Setrlimit", "Setsid", "SetsockoptByte", "SetsockoptICMPv6Filter", "SetsockoptIPMreq", "SetsockoptIPMreqn", "SetsockoptIPv6Mreq", "SetsockoptInet4Addr", "SetsockoptInt", "SetsockoptLinger", "SetsockoptString", "SetsockoptTimeval", "Settimeofday", "Setuid", "Setxattr", "Shutdown", "SlicePtrFromStrings", "Socket", "Socketpair", "Splice", "StartProcess", "Stat", "Statfs", "StringBytePtr", "StringByteSlice", "StringSlicePtr", "Symlink", "Sync", "SyncFileRange", "Sysinfo", "Tee", "Tgkill", "Times", "TimespecToNsec", "TimevalToNsec", "Truncate", "Umask", "Uname", "UnixCredentials", "UnixRights", "Unlink", "Unlinkat", "Unmount", "Unsetenv", "Unshare", "Ustat", "Utime", "Utimes", "UtimesNano", "Wait4", "Write", "Cmsghdr", "Conn", "Credential", "Dirent", "EpollEvent", "Errno", "AllThreadsSyscall", "AllThreadsSyscall6", "RawSyscall", "RawSyscall6", "Syscall", "Syscall6", "FdSet", "Flock_t", "Fsid", "ICMPv6Filter", "GetsockoptICMPv6Filter", "IPMreq", "GetsockoptIPMreq", "IPMreqn", "GetsockoptIPMreqn", "IPv6MTUInfo", "GetsockoptIPv6MTUInfo", "IPv6Mreq", "GetsockoptIPv6Mreq", "IfAddrmsg", "IfInfomsg", "Inet4Pktinfo", "Inet6Pktinfo", "InotifyEvent", "Iovec", "Linger", "Msghdr", "NetlinkMessage", "ParseNetlinkMessage", "NetlinkRouteAttr", "ParseNetlinkRouteAttr", "NetlinkRouteRequest", "NlAttr", "NlMsgerr", "NlMsghdr", "ProcAttr", "PtraceRegs", "RawConn", "RawSockaddr", "RawSockaddrAny", "RawSockaddrInet4", "RawSockaddrInet6", "RawSockaddrLinklayer", "RawSockaddrNetlink", "RawSockaddrUnix", "Rlimit", "RtAttr", "RtGenmsg", "RtMsg", "RtNexthop", "Rusage", "Signal", "SockFilter", "LsfJump", "LsfStmt", "SockFprog", "Sockaddr", "Accept", "Accept4", "Getpeername", "Getsockname", "Recvfrom", "Recvmsg", "SockaddrInet4", "SockaddrInet6", "SockaddrLinklayer", "SockaddrNetlink", "SockaddrUnix", "SocketControlMessage", "ParseSocketControlMessage", "Stat_t", "Statfs_t", "SysProcAttr", "SysProcIDMap", "Sysinfo_t", "TCPInfo", "Termios", "Time_t", "Time", "Timespec", "NsecToTimespec", "Timeval", "NsecToTimeval", "Timex", "Tms", "Ucred", "GetsockoptUcred", "ParseUnixCredentials", "Ustat_t", "Utimbuf", "Utsname", "WaitStatus"}, 338 | "syscall/js": {"CopyBytesToGo", "CopyBytesToJS", "Error", "Func", "FuncOf", "Type", "Value", "Global", "Null", "Undefined", "ValueOf", "ValueError"}, 339 | "testing": {"AllocsPerRun", "CoverMode", "Coverage", "Init", "Main", "RegisterCover", "RunBenchmarks", "RunExamples", "RunTests", "Short", "Testing", "Verbose", "B", "BenchmarkResult", "Benchmark", "Cover", "CoverBlock", "F", "InternalBenchmark", "InternalExample", "InternalFuzzTarget", "InternalTest", "M", "MainStart", "PB", "T", "TB"}, 340 | "testing/fstest": {"TestFS", "MapFS", "MapFile"}, 341 | "testing/internal/testdeps": {"TestDeps", "CheckCorpus", "CoordinateFuzzing", "ImportPath", "MatchString", "ReadCorpus", "ResetCoverage", "RunFuzzWorker", "SetPanicOnExit0", "SnapshotCoverage", "StartCPUProfile", "StartTestLog", "StopCPUProfile", "StopTestLog", "WriteProfileTo"}, 342 | "testing/iotest": {"DataErrReader", "ErrReader", "HalfReader", "NewReadLogger", "NewWriteLogger", "OneByteReader", "TestReader", "TimeoutReader", "TruncateWriter"}, 343 | "testing/quick": {"Check", "CheckEqual", "Value", "CheckEqualError", "CheckError", "Config", "Generator", "SetupError"}, 344 | "testing/slogtest": {"Run", "TestHandler"}, 345 | "text/scanner": {"TokenString", "Position", "Scanner"}, 346 | "text/tabwriter": {"Writer", "NewWriter"}, 347 | "text/template": {"HTMLEscape", "HTMLEscapeString", "HTMLEscaper", "IsTrue", "JSEscape", "JSEscapeString", "JSEscaper", "URLQueryEscaper", "ExecError", "FuncMap", "Template", "Must", "New", "ParseFS", "ParseFiles", "ParseGlob"}, 348 | "text/template/parse": {"IsEmptyTree", "Parse", "ActionNode", "BoolNode", "BranchNode", "BreakNode", "ChainNode", "CommandNode", "CommentNode", "ContinueNode", "DotNode", "FieldNode", "IdentifierNode", "NewIdentifier", "IfNode", "ListNode", "Mode", "NilNode", "Node", "NodeType", "NumberNode", "PipeNode", "Pos", "RangeNode", "StringNode", "TemplateNode", "TextNode", "Tree", "New", "VariableNode", "WithNode"}, 349 | "time": {"After", "Sleep", "Tick", "Duration", "ParseDuration", "Since", "Until", "Location", "FixedZone", "LoadLocation", "LoadLocationFromTZData", "Month", "ParseError", "Ticker", "NewTicker", "Time", "Date", "Now", "Parse", "ParseInLocation", "Unix", "UnixMicro", "UnixMilli", "Timer", "AfterFunc", "NewTimer", "Weekday"}, 350 | "time/tzdata": {}, 351 | "unicode": {"In", "Is", "IsControl", "IsDigit", "IsGraphic", "IsLetter", "IsLower", "IsMark", "IsNumber", "IsOneOf", "IsPrint", "IsPunct", "IsSpace", "IsSymbol", "IsTitle", "IsUpper", "SimpleFold", "To", "ToLower", "ToTitle", "ToUpper", "CaseRange", "Range16", "Range32", "RangeTable", "SpecialCase"}, 352 | "unicode/utf16": {"AppendRune", "Decode", "DecodeRune", "Encode", "EncodeRune", "IsSurrogate"}, 353 | "unicode/utf8": {"AppendRune", "DecodeLastRune", "DecodeLastRuneInString", "DecodeRune", "DecodeRuneInString", "EncodeRune", "FullRune", "FullRuneInString", "RuneCount", "RuneCountInString", "RuneLen", "RuneStart", "Valid", "ValidRune", "ValidString"}, 354 | "unsafe": {"Alignof", "Offsetof", "Sizeof", "String", "StringData", "ArbitraryType", "Slice", "SliceData", "IntegerType", "Pointer", "Add"}, 355 | } 356 | supportedPackages = maps.Keys(packageFunctions) 357 | 358 | autoComplete = append(supportedPackages, 359 | // language keywords 360 | "package", 361 | "import", 362 | "func", 363 | "var", 364 | "const", 365 | "return", 366 | "if", 367 | "else", 368 | "for", 369 | "range", 370 | "switch", 371 | "case", 372 | "default", 373 | "select", 374 | "break", 375 | "continue", 376 | "goto", 377 | "fallthrough", 378 | "defer", 379 | "go", 380 | "chan", 381 | "map", 382 | "struct", 383 | "interface", 384 | "type", 385 | "append", 386 | "cap", 387 | "close", 388 | "complex", 389 | "copy", 390 | "delete", 391 | "imag", 392 | "len", 393 | "make", 394 | "new", 395 | "panic", 396 | "real", 397 | "bool", 398 | "byte", 399 | "complex64", 400 | "complex128", 401 | "error", 402 | "float32", 403 | "float64", 404 | "int", 405 | "int8", 406 | "int16", 407 | "int32", 408 | "int64", 409 | "rune", 410 | "string", 411 | 412 | // used for goshell 413 | ".quit", 414 | ".vars", 415 | ".source", 416 | ".undo", 417 | ".help", 418 | ) 419 | ) 420 | -------------------------------------------------------------------------------- /autocomplete_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestWordCompleter(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | line string 13 | pos int 14 | head string 15 | completions []string 16 | tail string 17 | }{ 18 | { 19 | name: "Package known, function specified", 20 | line: "fmt.Pr", 21 | pos: 6, 22 | head: "fmt.", 23 | completions: []string{"Print", "Printf", "Println"}, 24 | tail: "", 25 | }, 26 | { 27 | name: "Empty line", 28 | line: "", 29 | pos: 0, 30 | head: "", 31 | completions: []string{}, 32 | tail: "", 33 | }, 34 | { 35 | name: "Package not known", 36 | line: "foo.", 37 | pos: 4, 38 | head: "foo.", 39 | completions: []string{}, 40 | tail: "", 41 | }, 42 | { 43 | name: "Package known, no function specified", 44 | line: "fmt.", 45 | pos: 4, 46 | head: "fmt.", 47 | completions: packageFunctions["fmt"], 48 | tail: "", 49 | }, 50 | { 51 | name: "Package known, function specified", 52 | line: "fmt.Pr", 53 | pos: 6, 54 | head: "fmt.", 55 | completions: []string{"Print", "Printf", "Println"}, 56 | tail: "", 57 | }, 58 | { 59 | name: "Package known, unkown function specified", 60 | line: "fmt.Zz", 61 | pos: 6, 62 | head: "fmt.Zz", 63 | completions: []string{}, 64 | tail: "", 65 | }, 66 | { 67 | name: "complete even in the middle of the line", 68 | line: "a:= struc random", 69 | pos: 9, 70 | head: "a:= ", 71 | completions: []string{"struct"}, 72 | tail: " random", 73 | }, 74 | } 75 | 76 | for _, tt := range tests { 77 | t.Run(tt.name, func(t *testing.T) { 78 | head, completions, tail := WordCompleter(tt.line, tt.pos) 79 | assert.Equal(t, tt.head, head) 80 | assert.ElementsMatch(t, tt.completions, completions) 81 | assert.Equal(t, tt.tail, tail) 82 | }) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /docs/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmedakef/goshell/8c7403a9d965d8ccb6624d612c90fb18727b1730/docs/example.gif -------------------------------------------------------------------------------- /generator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "text/template" 8 | 9 | "golang.org/x/tools/imports" 10 | ) 11 | 12 | func prepareProgram(templatePath string, commands []command, functions []function) (string, error) { 13 | // Read the template file 14 | t := template.Must(template.New("template.txt").Parse(programTemplate)) 15 | var buf bytes.Buffer 16 | err := t.Execute(&buf, map[string]any{ 17 | "commands": commands, 18 | "functions": functions, 19 | }) 20 | if err != nil { 21 | return "", err 22 | } 23 | 24 | return buf.String(), nil 25 | } 26 | 27 | func formatProgram(programPath string) error { 28 | 29 | output, err := imports.Process(programPath, nil, nil) 30 | if err != nil { 31 | fmt.Println("Error formatting the program:", err) 32 | return err 33 | } 34 | err = os.WriteFile(programPath, output, 0644) 35 | if err != nil { 36 | fmt.Println("Error writing the formatted program:", err) 37 | return err 38 | } 39 | 40 | return nil 41 | } 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ahmedakef/goshell 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/gocolly/colly v1.2.0 7 | github.com/peterh/liner v1.2.2 8 | github.com/stretchr/testify v1.8.4 9 | golang.org/x/exp v0.0.0-20240213143201-ec583247a57a 10 | golang.org/x/tools v0.18.0 11 | ) 12 | 13 | require ( 14 | github.com/PuerkitoBio/goquery v1.8.1 // indirect 15 | github.com/andybalholm/cascadia v1.3.1 // indirect 16 | github.com/antchfx/htmlquery v1.3.0 // indirect 17 | github.com/antchfx/xmlquery v1.3.18 // indirect 18 | github.com/antchfx/xpath v1.2.4 // indirect 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/gobwas/glob v0.2.3 // indirect 21 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 22 | github.com/golang/protobuf v1.5.2 // indirect 23 | github.com/kennygrant/sanitize v1.2.4 // indirect 24 | github.com/mattn/go-runewidth v0.0.3 // indirect 25 | github.com/pmezard/go-difflib v1.0.0 // indirect 26 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect 27 | github.com/temoto/robotstxt v1.1.2 // indirect 28 | golang.org/x/mod v0.15.0 // indirect 29 | golang.org/x/net v0.21.0 // indirect 30 | golang.org/x/sys v0.17.0 // indirect 31 | golang.org/x/text v0.14.0 // indirect 32 | google.golang.org/appengine v1.6.8 // indirect 33 | google.golang.org/protobuf v1.26.0 // indirect 34 | gopkg.in/yaml.v3 v3.0.1 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= 2 | github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= 3 | github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= 4 | github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= 5 | github.com/antchfx/htmlquery v1.3.0 h1:5I5yNFOVI+egyia5F2s/5Do2nFWxJz41Tr3DyfKD25E= 6 | github.com/antchfx/htmlquery v1.3.0/go.mod h1:zKPDVTMhfOmcwxheXUsx4rKJy8KEY/PU6eXr/2SebQ8= 7 | github.com/antchfx/xmlquery v1.3.18 h1:FSQ3wMuphnPPGJOFhvc+cRQ2CT/rUj4cyQXkJcjOwz0= 8 | github.com/antchfx/xmlquery v1.3.18/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA= 9 | github.com/antchfx/xpath v1.2.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= 10 | github.com/antchfx/xpath v1.2.4 h1:dW1HB/JxKvGtJ9WyVGJ0sIoEcqftV3SqIstujI+B9XY= 11 | github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= 12 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 13 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 14 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= 16 | github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= 17 | github.com/gocolly/colly v1.2.0 h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI= 18 | github.com/gocolly/colly v1.2.0/go.mod h1:Hof5T3ZswNVsOHYmba1u03W65HDWgpV5HifSuueE0EA= 19 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 20 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 21 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 22 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 23 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 24 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 25 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= 26 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 27 | github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= 28 | github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= 29 | github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= 30 | github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 31 | github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw= 32 | github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI= 33 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 34 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 35 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= 36 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= 37 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 38 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 39 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 40 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 41 | github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg= 42 | github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo= 43 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 44 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 45 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 46 | golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= 47 | golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= 48 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 49 | golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= 50 | golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 51 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 52 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 53 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 54 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 55 | golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= 56 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 57 | golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= 58 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 59 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 60 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 63 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 64 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 65 | golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 67 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 68 | golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= 71 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 72 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 73 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 74 | golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 75 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 76 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 77 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 78 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 79 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 80 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 81 | golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 82 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 83 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 84 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 85 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 86 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 87 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 88 | golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= 89 | golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= 90 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 91 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 92 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= 93 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 94 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 95 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 96 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 97 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 98 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 99 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 100 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 101 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "os" 8 | "os/signal" 9 | "path/filepath" 10 | "strings" 11 | "syscall" 12 | 13 | "github.com/peterh/liner" 14 | ) 15 | 16 | const ( 17 | version = "0.0.9" 18 | startUpMessage = "Go Shell - A Repl for Go" 19 | helpMessage = `Commands: 20 | .q(uit) exit Go Shell 21 | .v(ars) show all variable names 22 | .s(ource) print the source entered since startup 23 | .u(ndo) undo the last entry 24 | .h(elp) print this help message 25 | ` 26 | 27 | _programName = "goshell_program.go" 28 | ) 29 | 30 | func main() { 31 | versionFlag := flag.Bool("v", false, "Print the version") 32 | debugFlag := flag.Bool("debug", false, "debug mode") 33 | flag.Parse() 34 | if *versionFlag { 35 | fmt.Println(version) 36 | return 37 | } 38 | 39 | done := make(chan bool, 1) 40 | go waitForSignal(done) 41 | commandsChan := make(chan string, 1) 42 | continueChan := make(chan bool, 1) 43 | 44 | line, history_path := setupLiner() 45 | defer line.Close() 46 | 47 | fmt.Println(startUpMessage) 48 | fmt.Println(helpMessage) 49 | continueChan <- true 50 | go waitForInput(commandsChan, continueChan, done, line) 51 | 52 | path := filepath.Join(os.TempDir(), _programName) 53 | if *debugFlag { 54 | fmt.Println("Debug mode, using the file:", path) 55 | } 56 | manager := newManager(path) 57 | manager.cleanUp() 58 | 59 | for { 60 | select { 61 | case <-done: 62 | manager.cleanUp() 63 | if f, err := os.Create(history_path); err != nil { 64 | fmt.Println("Error writing history file: ", err) 65 | } else { 66 | line.WriteHistory(f) 67 | f.Close() 68 | } 69 | return 70 | case command := <-commandsChan: 71 | switch command { 72 | case ".quit", ".q": 73 | manager.cleanUp() 74 | return 75 | case ".vars", ".v": 76 | fmt.Println(manager.extractVariables()) 77 | case ".source", ".s": 78 | program, err := manager.getProgram() 79 | if err != nil { 80 | fmt.Println("Error geting the source code:", err) 81 | } else { 82 | fmt.Println(program) 83 | } 84 | case ".undo", ".u": 85 | manager.removeLastInput() 86 | case ".help", ".h": 87 | fmt.Println(helpMessage) 88 | 89 | default: 90 | if command == "" { 91 | break // ignore empty commands 92 | } 93 | err := manager.addInput(command) 94 | if err != nil { 95 | fmt.Println("Error parsing the input:", err) 96 | continueChan <- true 97 | continue 98 | } 99 | output, err := manager.runProgram() 100 | if err != nil { 101 | fmt.Println("Error running the program:", err) 102 | fmt.Println("Removing last input, type '.s(ource)' to see the program") 103 | manager.removeLastInput() 104 | } 105 | if output != "" { 106 | fmt.Print(output) 107 | } 108 | } 109 | } 110 | continueChan <- true 111 | } 112 | } 113 | 114 | func waitForInput(commands chan<- string, continueChan <-chan bool, done chan bool, line *liner.State) { 115 | for <-continueChan { 116 | command, err := line.Prompt(">>> ") 117 | if err == liner.ErrPromptAborted || err == io.EOF { 118 | done <- true 119 | return 120 | } else if err != nil { 121 | fmt.Println("Error reading input: ", err) 122 | done <- true 123 | } 124 | 125 | if command == "exit" { 126 | done <- true 127 | return 128 | } 129 | openBrackets := strings.Count(command, "{") 130 | openBrackets -= strings.Count(command, "}") 131 | if openBrackets > 0 { 132 | multiLineCommand := command + "\n" 133 | userExit := false 134 | for { 135 | identation := strings.Repeat(" ", openBrackets) 136 | if subCommand, err := line.Prompt("... " + identation); err == nil { 137 | if subCommand == "" { 138 | continue 139 | } 140 | multiLineCommand += subCommand + "\n" 141 | openBrackets += strings.Count(subCommand, "{") 142 | openBrackets -= strings.Count(subCommand, "}") 143 | if openBrackets == 0 { 144 | break 145 | } 146 | } else if err == io.EOF || err == liner.ErrPromptAborted { 147 | userExit = true 148 | break 149 | } else { 150 | fmt.Println("Error reading input: ", err) 151 | done <- true 152 | return 153 | } 154 | } 155 | if userExit { 156 | command = "" 157 | } else { 158 | command = multiLineCommand 159 | } 160 | } 161 | commands <- command 162 | if command != "" { 163 | line.AppendHistory(command) 164 | } 165 | } 166 | } 167 | 168 | func waitForSignal(done chan bool) { 169 | sigs := make(chan os.Signal, 1) 170 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 171 | 172 | sig := <-sigs 173 | fmt.Println("\nreceived:", sig) 174 | done <- true 175 | 176 | } 177 | 178 | func setupLiner() (*liner.State, string) { 179 | homedir, err := os.UserHomeDir() 180 | if err != nil { 181 | fmt.Println("Error getting home directory:", err) 182 | homedir = os.TempDir() 183 | } 184 | history_path := filepath.Join(homedir, ".goshell_history") 185 | line := liner.NewLiner() 186 | line.SetCtrlCAborts(true) 187 | line.SetMultiLineMode(true) 188 | line.SetTabCompletionStyle(liner.TabCircular) 189 | 190 | line.SetWordCompleter(WordCompleter) 191 | 192 | if f, err := os.Open(history_path); err == nil { 193 | line.ReadHistory(f) 194 | f.Close() 195 | } 196 | return line, history_path 197 | } 198 | -------------------------------------------------------------------------------- /manager.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/fs" 6 | "os" 7 | "os/exec" 8 | "strings" 9 | ) 10 | 11 | const ( 12 | _templatePath = "template.txt" 13 | ) 14 | 15 | type command struct { 16 | Src string 17 | variablesAssigned []string 18 | variablesDeclared []string 19 | isExpression bool 20 | Hidden bool 21 | isCallExpression bool 22 | calleeName string 23 | } 24 | 25 | type function struct { 26 | Name string 27 | Src string 28 | returnVariables []string 29 | } 30 | 31 | type Manager struct { 32 | commands []command 33 | functions []function 34 | functionsIndex map[string]function 35 | lastInputFunctionDef bool 36 | programPath string 37 | templatePath string 38 | } 39 | 40 | func newManager(programPath string) *Manager { 41 | return &Manager{ 42 | commands: []command{}, 43 | functions: []function{}, 44 | functionsIndex: map[string]function{}, 45 | programPath: programPath, 46 | templatePath: _templatePath, 47 | } 48 | } 49 | 50 | func (m *Manager) addInput(input string) error { 51 | if isFunctionDeclaration(input) { 52 | err := m.addFunction(input) 53 | if err != nil { 54 | return err 55 | } 56 | m.lastInputFunctionDef = true 57 | return nil 58 | } 59 | 60 | err := m.addCommand(input) 61 | if err != nil { 62 | return err 63 | } 64 | m.lastInputFunctionDef = false 65 | return nil 66 | } 67 | 68 | func (m *Manager) addCommand(input string) error { 69 | av, err := ParseStatement(input) 70 | if err != nil { 71 | return err 72 | } 73 | m.commands = append(m.commands, command{ 74 | Src: input, 75 | variablesAssigned: av.VariablesAssigned, 76 | variablesDeclared: av.VariablesDeclared, 77 | isExpression: av.IsExpression, 78 | isCallExpression: av.callExpression, 79 | calleeName: av.calleeName, 80 | }) 81 | return nil 82 | } 83 | 84 | func (m *Manager) addFunction(input string) error { 85 | function, err := ParseFunction(input) 86 | if err != nil { 87 | return err 88 | } 89 | m.functions = append(m.functions, function) 90 | m.functionsIndex[function.Name] = function 91 | return nil 92 | } 93 | 94 | func (m *Manager) removeLastInput() { 95 | if m.lastInputFunctionDef { 96 | functionName := m.functions[len(m.functions)-1].Name 97 | delete(m.functionsIndex, functionName) 98 | m.functions = m.functions[:len(m.functions)-1] 99 | } else { 100 | m.commands = m.commands[:len(m.commands)-1] 101 | } 102 | } 103 | 104 | func (m *Manager) runProgram() (string, error) { 105 | commands := m.prepareCommands() 106 | program, err := prepareProgram(m.templatePath, commands, m.functions) 107 | if err != nil { 108 | return "", err 109 | } 110 | 111 | // Save the substituted template to the output file 112 | err = os.WriteFile(m.programPath, []byte(program), fs.FileMode(0644)) 113 | if err != nil { 114 | return "", err 115 | } 116 | 117 | err = formatProgram(m.programPath) 118 | if err != nil { 119 | return "", err 120 | } 121 | 122 | cmd := exec.Command("go", "run", m.programPath) 123 | output, err := cmd.CombinedOutput() 124 | if err != nil { 125 | fmt.Println(string(output)) 126 | return "", err 127 | } 128 | return string(output), nil 129 | } 130 | 131 | func (m *Manager) getProgram() (string, error) { 132 | commands := m.prepareCommands() 133 | return prepareProgram(m.templatePath, commands, m.functions) 134 | } 135 | 136 | func (m *Manager) prepareCommands() []command { 137 | commands := make([]command, len(m.commands)) 138 | copy(commands, m.commands) 139 | 140 | for i := range commands { 141 | if !commands[i].isExpression { 142 | continue 143 | } 144 | if i < len(commands)-1 || m.lastInputFunctionDef { 145 | // remove all expression commands and function definitions before the last one 146 | commands[i].Hidden = true 147 | continue 148 | } 149 | if strings.HasPrefix(commands[i].Src, "fmt.Print") { 150 | // expression already contain printing 151 | continue 152 | } 153 | if commands[i].isCallExpression { 154 | if len(m.functionsIndex[commands[i].calleeName].returnVariables) == 0 { 155 | // function call without return value 156 | continue 157 | } 158 | } 159 | commands[i].Src = commandPrintted(commands[i].Src) 160 | } 161 | commands = append(commands, m.useCallStatement()) 162 | return commands 163 | } 164 | 165 | func (m *Manager) extractVariables() []string { 166 | variables := []string{} 167 | for _, command := range m.commands { 168 | variables = append(variables, command.variablesDeclared...) 169 | variables = append(variables, command.variablesAssigned...) 170 | } 171 | return variables 172 | } 173 | 174 | func (m *Manager) useCallStatement() command { 175 | variables := m.extractVariables() 176 | if len(variables) == 0 { 177 | return command{} 178 | } 179 | return command{ 180 | Src: fmt.Sprintf("use(%s)", strings.Join(variables, ", ")), 181 | isExpression: true, 182 | } 183 | } 184 | 185 | func commandPrintted(command string) string { 186 | return fmt.Sprintf("fmt.Printf(%s, %s)", "\"%#v\\n\"", command) 187 | } 188 | 189 | func (m *Manager) cleanUp() { 190 | os.Remove(m.programPath) 191 | } 192 | -------------------------------------------------------------------------------- /manager_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "path" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestManager_RunProgram(t *testing.T) { 12 | tests := []struct { 13 | name string 14 | input []string 15 | expectedOutput string 16 | expectedError error 17 | }{ 18 | { 19 | name: "simple addition", 20 | input: []string{ 21 | "1+1", 22 | }, 23 | expectedOutput: "2\n", 24 | expectedError: nil, 25 | }, 26 | { 27 | name: "function declaration and call", 28 | input: []string{ 29 | "func add(a int, b int) int { return a+b }", 30 | "add(2,3)", 31 | }, 32 | expectedOutput: "5\n", 33 | expectedError: nil, 34 | }, 35 | { 36 | name: "declation then experiment", 37 | input: []string{ 38 | "a:=1", 39 | "a", 40 | "a=3", 41 | "a", 42 | }, 43 | expectedOutput: "3\n", 44 | expectedError: nil, 45 | }, 46 | { 47 | name: "slice initialization", 48 | input: []string{ 49 | "a:= []int{1}", 50 | "a", 51 | }, 52 | expectedOutput: "[]int{1}\n", 53 | expectedError: nil, 54 | }, 55 | { 56 | name: "assignment, experiment, function declaration", 57 | input: []string{ 58 | "a:=1", 59 | "a", 60 | "func add(a int, b int) int { return a+b }", 61 | }, 62 | expectedOutput: "", 63 | expectedError: nil, 64 | }, 65 | { 66 | name: "function declaration without return variables and call", 67 | input: []string{ 68 | "func x() { fmt.Println(3) }", 69 | "x()", 70 | }, 71 | expectedOutput: "3\n", 72 | expectedError: nil, 73 | }, 74 | { 75 | name: "slice indexin", 76 | input: []string{ 77 | "a:= []int{1}", 78 | "a[0] = 2", 79 | "a[0]", 80 | }, 81 | expectedOutput: "2\n", 82 | expectedError: nil, 83 | }, 84 | } 85 | 86 | for _, tt := range tests { 87 | t.Run(tt.name, func(t *testing.T) { 88 | // Create a temporary directory for the program file 89 | tempDir, err := os.MkdirTemp("", "test-program") 90 | if err != nil { 91 | t.Fatal("Failed to create temporary directory:", err) 92 | } 93 | defer os.RemoveAll(tempDir) 94 | 95 | // Create a Manager instance 96 | m := newManager(path.Join(tempDir, "program.go")) 97 | 98 | for _, input := range tt.input { 99 | m.addInput(input) 100 | } 101 | output, err := m.runProgram() 102 | assert.Equal(t, tt.expectedError, err) 103 | assert.Equal(t, tt.expectedOutput, output) 104 | 105 | }) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /parser.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/parser" 7 | "go/token" 8 | "strings" 9 | ) 10 | 11 | func ParseFunction(x string) (function, error) { 12 | function := function{ 13 | Src: x, 14 | } 15 | code := "package p;" + x 16 | file, err := parser.ParseFile(token.NewFileSet(), "", code, 0) 17 | if err != nil { 18 | return function, err 19 | } 20 | funcDecl := file.Decls[0].(*ast.FuncDecl) 21 | function.Name = funcDecl.Name.Name 22 | returnVariables := funcDecl.Type.Results 23 | if returnVariables == nil { 24 | return function, nil 25 | } 26 | for _, variable := range returnVariables.List { 27 | ident, ok := variable.Type.(*ast.Ident) 28 | if ok { 29 | function.returnVariables = append(function.returnVariables, ident.Name) 30 | } 31 | } 32 | return function, nil 33 | } 34 | 35 | // ParseStatement is a modified version of go/parser.ParseExpr 36 | func ParseStatement(x string) (*AstVisitor, error) { 37 | // parse x within the context of a complete package for correct scopes; 38 | // put x alone on a separate line (handles line comments), followed by a ';' 39 | // to force an error if the expression is incomplete 40 | 41 | var node ast.Node 42 | code := "package p;func _(){" + x + "\n;}" 43 | file, err := parser.ParseFile(token.NewFileSet(), "", code, 0) 44 | if err != nil { 45 | return nil, err 46 | } 47 | node = file.Decls[0].(*ast.FuncDecl).Body.List[0] 48 | 49 | av := new(AstVisitor) 50 | ast.Walk(av, node) 51 | return av, nil 52 | } 53 | 54 | // AstVisitor implements a ast.Visitor and collect variable and import info 55 | type AstVisitor struct { 56 | VariablesAssigned []string 57 | VariablesDeclared []string 58 | Imports []string 59 | Functions []string 60 | IsExpression bool 61 | callExpression bool // this is a call to function or method expression 62 | calleeName string // name of the function or method being called 63 | } 64 | 65 | // Visit inspects the type of a Node to detect a Assignment, Declaration or Import 66 | func (av *AstVisitor) Visit(node ast.Node) ast.Visitor { 67 | switch node := node.(type) { 68 | case *ast.AssignStmt: 69 | for _, each := range node.Lhs { 70 | // assert on each type 71 | switch v := each.(type) { 72 | case *ast.Ident: 73 | av.VariablesAssigned = append(av.VariablesAssigned, v.Name) 74 | case *ast.IndexExpr: 75 | // like a[0] = 1 76 | // variable already assigned 77 | default: 78 | fmt.Printf("I don't know about type %T!\n", each) 79 | } 80 | } 81 | case *ast.DeclStmt: 82 | for _, each := range node.Decl.(*ast.GenDecl).Specs { 83 | valueSpec, ok := each.(*ast.ValueSpec) 84 | if ok { 85 | for _, other := range valueSpec.Names { 86 | av.VariablesDeclared = append(av.VariablesDeclared, other.Name) 87 | } 88 | } 89 | } 90 | case *ast.ImportSpec: 91 | av.Imports = append(av.Imports, node.Path.Value) 92 | case *ast.ExprStmt: 93 | av.IsExpression = true 94 | callExpr, ok := node.X.(*ast.CallExpr) 95 | if ok { 96 | ident, ok := callExpr.Fun.(*ast.Ident) 97 | if ok { 98 | av.callExpression = true 99 | av.calleeName = ident.Name 100 | } 101 | } 102 | case *ast.IncDecStmt: // like a++ or a-- 103 | } 104 | return av 105 | } 106 | 107 | func isFunctionDeclaration(statement string) bool { 108 | return strings.HasPrefix(statement, "func") 109 | } 110 | -------------------------------------------------------------------------------- /parser_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestParse(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | input string 13 | expectedAssigned []string 14 | expectedDeclared []string 15 | expectedError error 16 | }{ 17 | { 18 | name: "simple expression1", 19 | input: "1 + 2", 20 | }, 21 | { 22 | name: "simple print", 23 | input: "fmt.Println(\"Hello, World!\")", 24 | }, 25 | { 26 | name: "assignment", 27 | input: "a:= 1", 28 | expectedAssigned: []string{"a"}, 29 | }, 30 | { 31 | name: "assignment without colon", 32 | input: "a = 1", 33 | expectedAssigned: []string{"a"}, 34 | }, 35 | } 36 | 37 | for _, tt := range tests { 38 | t.Run(tt.name, func(t *testing.T) { 39 | av, err := ParseStatement(tt.input) 40 | if tt.expectedError != nil { 41 | assert.Equal(t, tt.expectedError, err) 42 | return 43 | } 44 | assert.NoError(t, err) 45 | 46 | assert.Equal(t, tt.expectedAssigned, av.VariablesAssigned) 47 | assert.Equal(t, tt.expectedDeclared, av.VariablesDeclared) 48 | }) 49 | } 50 | } 51 | 52 | func TestParseFunction(t *testing.T) { 53 | tests := []struct { 54 | name string 55 | input string 56 | expectedName string 57 | expectedReturn []string 58 | expectedError error 59 | }{ 60 | { 61 | name: "valid expression", 62 | input: "func add(a int, b int) int { return a+b }", 63 | expectedName: "add", 64 | expectedReturn: []string{"int"}, 65 | }, 66 | } 67 | 68 | for _, tt := range tests { 69 | t.Run(tt.name, func(t *testing.T) { 70 | result, err := ParseFunction(tt.input) 71 | if tt.expectedError != nil { 72 | assert.Equal(t, tt.expectedError, err) 73 | return 74 | } 75 | assert.NoError(t, err) 76 | 77 | assert.Equal(t, tt.expectedName, result.Name) 78 | assert.Equal(t, tt.expectedReturn, result.returnVariables) 79 | }) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /scripts/fetcher.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "os/exec" 10 | "time" 11 | 12 | "github.com/gocolly/colly" 13 | ) 14 | 15 | const ( 16 | version = "0.0.1" 17 | listURI = "https://pkg.go.dev/std/" 18 | packagesFunctionsFiles = "pkgFunctions.json" 19 | packagesNamesFiles = "pkgNames.json" 20 | listPageSelector = "article.go-Main-article table tbody tr" 21 | ) 22 | 23 | var ( 24 | mapOfLibs = map[string][]string{} 25 | debugFlag = flag.Bool("debug", false, "debug mode") 26 | ) 27 | 28 | func main() { 29 | flag.Parse() 30 | listPageCollector := colly.NewCollector() 31 | listPageCollector.SetRequestTimeout(120 * time.Second) 32 | 33 | listPageCollector.OnRequest(func(r *colly.Request) { 34 | fmt.Println("Visiting", r.URL) 35 | }) 36 | listPageCollector.OnHTML(listPageSelector, listPageHandler) 37 | listPageCollector.OnResponse(func(r *colly.Response) { 38 | if !*debugFlag { 39 | return 40 | } 41 | err := os.WriteFile("listResponse.html", r.Body, 0644) 42 | if err != nil { 43 | fmt.Println(err) 44 | } 45 | }) 46 | err := listPageCollector.Visit(listURI) 47 | if err != nil { 48 | fmt.Println(err) 49 | } 50 | 51 | jsonData, err := json.Marshal(mapOfLibs) 52 | if err != nil { 53 | fmt.Println(err) 54 | } 55 | os.WriteFile(packagesFunctionsFiles, jsonData, 0644) 56 | commands := [][]string{ 57 | {"sed", "-i", "", "s/\\[\\]/{}/g", packagesFunctionsFiles}, 58 | {"sed", "-i", "", "s/\\[/{/g", packagesFunctionsFiles}, 59 | {"sed", "-i", "", "s/\\]/}/g", packagesFunctionsFiles}, 60 | {"sed", "-i", "", "s/},/},\\n/g", packagesFunctionsFiles}, 61 | } 62 | executeCommands(commands) 63 | 64 | } 65 | 66 | func executeCommands(commands [][]string) { 67 | for _, command := range commands { 68 | cmd := exec.Command(command[0], command[1:]...) 69 | fmt.Println("Running command", cmd.String()) 70 | var stderr bytes.Buffer 71 | cmd.Stderr = &stderr 72 | err := cmd.Run() 73 | if err != nil { 74 | fmt.Println("Stderr:", stderr.String()) 75 | fmt.Println(err) 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /scripts/visiter.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | "time" 8 | 9 | "log" 10 | 11 | "github.com/gocolly/colly" 12 | ) 13 | 14 | const ( 15 | detailURIBase = "https://pkg.go.dev/" 16 | detailsPageSelector = "li.DocNav-functions,li.DocNav-types" 17 | ) 18 | 19 | func listPageHandler(el *colly.HTMLElement) { 20 | libPartOfURI := el.ChildAttr("td:first-child div div:first-child a", "href") 21 | if libPartOfURI == "" { 22 | // nested inside a directory 23 | libPartOfURI = el.ChildAttr("td:first-child div span:first-child a", "href") 24 | if libPartOfURI == "" { 25 | // the directory itself 26 | return 27 | } 28 | } 29 | elID := el.ChildAttr("td:first-child", "data-id") 30 | if elID == "" { 31 | elID = el.Attr("data-id") 32 | if elID == "" { 33 | log.Println("No data-id found") 34 | return 35 | } 36 | } 37 | packagename := strings.Join(strings.Split(elID, "-"), "/") 38 | 39 | functionsNames := visitPackage(detailURIBase + libPartOfURI) 40 | 41 | mapOfLibs[packagename] = functionsNames 42 | } 43 | 44 | func visitPackage(libURI string) []string { 45 | membersNames := []string{} 46 | // for some reason the "li.DocNav-types > ul > li > ul > li > a" selector return an item twice 47 | membrersLookup := map[string]struct{}{} 48 | detailsPageCollector := colly.NewCollector() 49 | detailsPageCollector.SetRequestTimeout(120 * time.Second) 50 | detailsPageCollector.OnRequest(func(r *colly.Request) { 51 | log.Println("Visiting", r.URL) 52 | }) 53 | detailsPageCollector.OnHTML(detailsPageSelector, func(category *colly.HTMLElement) { 54 | category.ForEach("ul > li", func(i int, e *colly.HTMLElement) { 55 | if category.Attr("class") == "DocNav-functions" { 56 | functionText := strings.TrimSpace(e.ChildText("a:first-child")) 57 | function := clearFunctionName(functionText) 58 | membersNames = append(membersNames, function) 59 | } else if category.Attr("class") == "DocNav-types" { 60 | e.ForEach("li.DocNav-types > ul > li > a", func(i int, el *colly.HTMLElement) { 61 | text := strings.TrimSpace(el.Text) 62 | if strings.Contains(text, "type") { 63 | typeCleared := strings.Split(text, "type ")[1] 64 | if _, ok := membrersLookup[typeCleared]; !ok { 65 | membersNames = append(membersNames, typeCleared) 66 | membrersLookup[typeCleared] = struct{}{} 67 | } 68 | } 69 | }) 70 | e.ForEach("li.DocNav-types > ul > li > ul > li > a", func(i int, el *colly.HTMLElement) { 71 | text := strings.TrimSpace(el.Text) 72 | if strings.HasPrefix(text, "(") { 73 | // type methods, skipped for now as it is complex to support them 74 | return 75 | } 76 | function := clearFunctionName(text) 77 | if _, ok := membrersLookup[function]; !ok { 78 | membersNames = append(membersNames, function) 79 | membrersLookup[function] = struct{}{} 80 | } 81 | 82 | }) 83 | } 84 | }) 85 | }) 86 | 87 | detailsPageCollector.OnResponse(func(r *colly.Response) { 88 | if !*debugFlag { 89 | return 90 | } 91 | err := os.WriteFile("detailsResponse.html", r.Body, 0644) 92 | if err != nil { 93 | fmt.Println(err) 94 | } 95 | }) 96 | 97 | err := detailsPageCollector.Visit(libURI) 98 | if err != nil { 99 | log.Println(err) 100 | } 101 | 102 | return membersNames 103 | } 104 | 105 | func clearFunctionName(function string) string { 106 | return strings.Split(function, "(")[0] 107 | } 108 | -------------------------------------------------------------------------------- /template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var programTemplate = ` 4 | package main 5 | {{range .functions}} 6 | {{.Src}} 7 | {{end}} 8 | func main() { 9 | {{- range .commands}} 10 | {{- if not .Hidden}} 11 | {{.Src -}} 12 | {{end -}} 13 | {{end}} 14 | } 15 | 16 | // used to avoid "declared and not used" error 17 | func use(vals ...any) { 18 | for _, val := range vals { 19 | _ = val 20 | } 21 | }` 22 | --------------------------------------------------------------------------------