├── extension.png ├── extension@2x.png ├── .prettierrc.json ├── Images └── extension │ └── Go-Nova-Banner.png ├── .gitignore ├── Tests ├── go.mod.sample └── basictest.go ├── LICENSE.md ├── .all-contributorsrc ├── extension.json ├── Syntaxes ├── Go-Template.xml ├── Go-Mod.xml └── Go.xml ├── Scripts ├── lsp.js └── main.js ├── Completions └── Go.xml ├── CHANGELOG.md └── README.md /extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/Go.novaextension/HEAD/extension.png -------------------------------------------------------------------------------- /extension@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/Go.novaextension/HEAD/extension@2x.png -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true 6 | } -------------------------------------------------------------------------------- /Images/extension/Go-Nova-Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GwynethLlewelyn/Go.novaextension/HEAD/Images/extension/Go-Nova-Banner.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Stupid macOS temporary files 2 | 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | # Stuff from the Nova editor 32 | .nova 33 | -------------------------------------------------------------------------------- /Tests/go.mod.sample: -------------------------------------------------------------------------------- 1 | module golang.org/x/net 2 | 3 | go 1.11 4 | 5 | require ( 6 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 7 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f 8 | golang.org/x/text v0.3.3 9 | ) 10 | 11 | replace ( 12 | github.com/etcd-io/bbolt => go.etcd.io/bbolt v1.3.5 13 | github.com/mholt/caddy => github.com/caddyserver/caddy v1.0.5 14 | github.com/nats-io/go-nats => github.com/nats-io/nats.go v1.8.1 15 | github.com/nats-io/go-nats-streaming => github.com/nats-io/stan.go v0.5.0 16 | github.com/nats-io/nats => github.com/nats-io/nats.go v1.8.0 17 | go.uber.org/atomic => github.com/uber-go/atomic v1.5.0 18 | ) -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2020-2021 Gwyneth Llewelyn, John Fieber, Daniel Seripap 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 | 23 | Parts of the code may be subject to the [Microsoft Public License (MS-PL)](https://opensource.org/licenses/MS-PL) -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "seripap", 10 | "name": "Daniel Seripap", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/683200?v=4", 12 | "profile": "http://daniel.seripap.com", 13 | "contributions": [ 14 | "code" 15 | ] 16 | }, 17 | { 18 | "login": "tooolbox", 19 | "name": "Matt Mc", 20 | "avatar_url": "https://avatars.githubusercontent.com/u/4984708?v=4", 21 | "profile": "https://github.com/tooolbox", 22 | "contributions": [ 23 | "ideas", 24 | "question" 25 | ] 26 | }, 27 | { 28 | "login": "jfieber", 29 | "name": "John Fieber", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/113956?v=4", 31 | "profile": "https://github.com/jfieber", 32 | "contributions": [ 33 | "code", 34 | "ideas", 35 | "doc" 36 | ] 37 | }, 38 | { 39 | "login": "apexskier", 40 | "name": "Cameron Little", 41 | "avatar_url": "https://avatars.githubusercontent.com/u/329222?v=4", 42 | "profile": "https://camlittle.com", 43 | "contributions": [ 44 | "ideas" 45 | ] 46 | } 47 | ], 48 | "contributorsPerLine": 7, 49 | "projectName": "Go.novaextension", 50 | "projectOwner": "GwynethLlewelyn", 51 | "repoType": "github", 52 | "repoHost": "https://github.com", 53 | "skipCi": true 54 | } 55 | -------------------------------------------------------------------------------- /Tests/basictest.go: -------------------------------------------------------------------------------- 1 | // Testing formatting/imports 2 | package main 3 | 4 | import ( 5 | _ "errors" 6 | "os" 7 | "fmt" 8 | myPtr "golang.org/x/net/html/atom" // hnmrs" 9 | ) 10 | 11 | // foo bar cat. 12 | func foo(s string) string { 13 | return s 14 | } 15 | 16 | type User struct { 17 | FirstName string 18 | LastName string 19 | Age int 20 | Admin bool 21 | } 22 | 23 | // myFunc does something not very useful. 24 | func myFunc(a string, b string) bool { 25 | return a != b // no? why the weird error? 26 | } 27 | 28 | // anotherFunc serves no purpose whatsoever. 29 | func anotherFunc(a, b string) string { 30 | return a + b 31 | } 32 | 33 | // Greeting is a list of methods. 34 | func (u *User) Greeting(what string, users User) string { 35 | var blip myPtr.Atom 36 | return fmt.Sprintf("Dear %s %s %v: %s", u.FirstName, u.LastName, blip, what) 37 | } 38 | 39 | /* 40 | Hey, this is a comment. 41 | */ 42 | // TODO(gwyneth): Change everything! 43 | func main() { 44 | // huh 45 | // add a comment here 46 | // and another 47 | /* inclie */ 48 | /// There were some issues with 3 slashes at the beginning 49 | 50 | // var a = 'w' 51 | var a []byte 52 | var v = 1 53 | t := make([]byte, 1, 2) 54 | b := append(t, a[0], byte(1), 0.00, byte(0x08)) 55 | complexNumber := -4.0436 + 3.76e-5i // almost correctly formatted/captured by the regex 56 | exponential := -3.167252381e-12 57 | hex := 0x0f - 0x0f0f 58 | octal := 0777 59 | v = octal + hex 60 | 61 | var ( 62 | google []byte 63 | x string 64 | c int64 65 | ) 66 | Main := "var" 67 | heredoc := `hi` 68 | fmt.Println("nothing works...", heredoc) // was 69 | fmt.Println("Clearly nothing yet...", google, x, c, t, b, v, complexNumber, exponential, octal) 70 | fmt.Println("wth?...") 71 | println("something") 72 | fmt.Printf("%s%v\n", Main, hex) 73 | 74 | var user User // 75 | 76 | pointer := &user 77 | 78 | i := 1 79 | 80 | var err error 81 | 82 | if i > 0 && err != nil { 83 | // do something 84 | pointer.Greeting(os.TempDir(), *pointer) 85 | } else { 86 | // do something else somewhere 87 | fmt.Println("Something else") 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /extension.json: -------------------------------------------------------------------------------- 1 | { 2 | "identifier": "gwynethllewelyn.Go", 3 | "name": "Go", 4 | "organization": "Gwyneth Llewelyn", 5 | "description": "Go Language Definition for Nova", 6 | "version": "0.4.3", 7 | "min_runtime": "6.0", 8 | "bugs": "https://github.com/GwynethLlewelyn/Go.novaextension/issues", 9 | "repository": "https://github.com/GwynethLlewelyn/Go.novaextension", 10 | "homepage": "https://gwynethllewelyn.net", 11 | "funding": "https://www.paypal.com/paypalme/gwynethllewelyn", 12 | "keywords": ["go", "golang"], 13 | "license": "MIT", 14 | "categories": ["completions", "languages"], 15 | "main": "main.js", 16 | "activationEvents": ["onLanguage:Go", "onWorkspaceContains:*.go"], 17 | "entitlements": { 18 | "process": true, 19 | "requests": false, 20 | "filesystem": "readwrite" 21 | }, 22 | "config": [ 23 | { 24 | "key": "go-nova.enable-gopls", 25 | "title": "Enable Language Server", 26 | "description": "Use the `gopls` language server for enhanced functionality. The `gopls` command should be installed in your search path, or you can specify the full path below.", 27 | "link": "https://github.com/golang/tools/blob/master/gopls/README.md", 28 | "type": "boolean", 29 | "default": false 30 | }, 31 | { 32 | "key": "go-nova.gopls-path", 33 | "title": "Language Server Command", 34 | "link": "https://github.com/golang/tools/blob/master/gopls/README.md", 35 | "description": "The command name to start the `gopls` language server. Use an absolute path here if `gopls` is not in your search path ($PATH environment variable).", 36 | "type": "path", 37 | "default": "gopls", 38 | "filetype": ["public.unix-executable"] 39 | }, 40 | { 41 | "key": "go-nova.format-on-save", 42 | "title": "(Experimental) Format/Organize Imports when saving file (DANGEROUS!)", 43 | "description": "When saving, use `gopls` to format file according to Go formatting standards and organize imports (the equivalent of executing `gofmt`, `goimports`, `goreturns`). Requires `gopls` language server to be active.\nWARNING: For experimental purposes ONLY! Currently it WILL DESTROY YOUR FILES!", 44 | "type": "boolean", 45 | "default": false 46 | }, 47 | { 48 | "key": "go-nova.use-staticcheck", 49 | "title": "(Experimental) Use https://staticcheck.io for further analysis", 50 | "description": "Use `gopls` in conjunction with https://staticcheck.io for further analysis of the code. This also requires `gopls` language server to be active.", 51 | "type": "boolean", 52 | "default": false 53 | } 54 | ], 55 | "commands": { 56 | "editor": [ 57 | { 58 | "title": "Jump to Definition", 59 | "command": "go.jumpToDefinition", 60 | "when": "editorHasFocus", 61 | "filters": { 62 | "syntaxes": ["go"] 63 | } 64 | }, 65 | { 66 | "title": "Organize Imports", 67 | "command": "go.organizeImports", 68 | "when": "editorHasFocus", 69 | "filters": { 70 | "syntaxes": ["go"] 71 | } 72 | }, 73 | { 74 | "title": "Format File", 75 | "command": "go.formatFile", 76 | "when": "editorHasFocus", 77 | "filters": { 78 | "syntaxes": ["go"] 79 | } 80 | } 81 | ] 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Syntaxes/Go-Template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Go templates 5 | markup 6 | tpl 7 | html 8 | 9 | 10 | 11 | tpl 12 | 13 | 14 | 15 | 16 | $ 17 | 18 | 19 | 20 | 21 | 22 | <(?!(?i:\!DOCTYPE|area|base|basefront|br|col|embed|frame|hr|img|input|keygen|link|meta|object|param|source)|[^>]*/>)([A-Za-z0-9]+)(?=\s|>)[^>]*>(?!.*</\1>) 23 | 24 | 25 | [\s]*</([A-Za-z0-9]+)(?=\s|>)[^>]*> 26 | 27 | 28 | 29 | 30 | 31 | 32 | <!-- 33 | 34 | 35 | --> 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | \{\{ 65 | 66 | 67 | 68 | \}\} 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | (\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) 83 | 84 | 85 | 86 | 87 | (\.[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*) 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Syntaxes/Go-Mod.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Go Modules List 5 | structured 6 | mod 7 | 8 | 9 | 10 | 11 | go.mod 12 | 13 | 14 | 15 | 16 | (\([^)\"']*$) 17 | 18 | 19 | ^\s*(\s*/\*.*\*/\s*)*[\)\\] 20 | 21 | 22 | 23 | 24 | 25 | // 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | (module)\s*([a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9_\.\/]+) 43 | 44 | 45 | 46 | 47 | 48 | 49 | (go)\s*([0-9]*\.?[0-9]+\.?[0-9]*) 50 | 51 | 52 | 53 | 54 | 55 | 56 | \/\/.*$ 57 | 58 | 59 | 60 | 61 | 62 | (require)\s*(\() 63 | 64 | 65 | 66 | 67 | (\)) 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | (replace)\s*(\() 79 | 80 | 81 | 82 | 83 | (\)) 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | true 100 | false 101 | 102 | 103 | 104 | 105 | \b(\-|\+)?(?:\d+(?:\.\d*)?|(?:\.\d+))\b 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | "(?:[^"\\]|\\.)*(?:"|$) 114 | 115 | 116 | '(?:[^'\\]|\\.)*(?:'|$) 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | module 126 | go 127 | require 128 | replace 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | => 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | [a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9\-_\.\/]+ 147 | 148 | 149 | 150 | 151 | 152 | 153 | \s*([a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9\-_\.\/]+)\s*(\S*).*$ 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | ^\s*([a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9\-_\.\/]+)\s(\=\>)\s*([a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9\-_\.\/]+)\s*([\w\.\-]*).*$ 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /Scripts/lsp.js: -------------------------------------------------------------------------------- 1 | // Turn a Nova start-end range to an LSP row-column range. 2 | // From https://github.com/apexskier/nova-typescript 3 | // 4 | // Adding the original license terms from Microsoft, as shown on @apexskier's 5 | // own files (gwyneth 20200130) 6 | // Probably this is the [Microsoft Public License (MS-PL)](https://opensource.org/licenses/MS-PL) 7 | // 8 | /*! ***************************************************************************** 9 | Copyright (c) Microsoft Corporation. 10 | 11 | Permission to use, copy, modify, and/or distribute this software for any 12 | purpose with or without fee is hereby granted. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 15 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 16 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 17 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 18 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 19 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 | PERFORMANCE OF THIS SOFTWARE. 21 | ***************************************************************************** */ 22 | // 23 | exports.RangeToLspRange = function (document, range) { 24 | const fullContents = document.getTextInRange(new Range(0, document.length)); 25 | let chars = 0; 26 | let startLspRange; 27 | const lines = fullContents.split(document.eol); 28 | for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { 29 | const lineLength = lines[lineIndex].length + document.eol.length; 30 | if (!startLspRange && chars + lineLength >= range.start) { 31 | const character = range.start - chars; 32 | startLspRange = { line: lineIndex, character }; 33 | } 34 | if (startLspRange && chars + lineLength >= range.end) { 35 | const character = range.end - chars; 36 | return { 37 | start: startLspRange, 38 | end: { line: lineIndex, character }, 39 | }; 40 | } 41 | chars += lineLength; 42 | } 43 | return null; 44 | }; 45 | 46 | // Turn an LSP row-column range to a Nova start-end range. 47 | // From https://github.com/apexskier/nova-typescript 48 | exports.LspRangeToRange = function (document, range) { 49 | const fullContents = document.getTextInRange(new Range(0, document.length)); 50 | let rangeStart = 0; 51 | let rangeEnd = 0; 52 | let chars = 0; 53 | const lines = fullContents.split(document.eol); 54 | for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { 55 | const lineLength = lines[lineIndex].length + document.eol.length; 56 | if (range.start.line === lineIndex) { 57 | rangeStart = chars + range.start.character; 58 | } 59 | if (range.end.line === lineIndex) { 60 | rangeEnd = chars + range.end.character; 61 | break; 62 | } 63 | chars += lineLength; 64 | } 65 | if (nova.inDevMode()) { 66 | console.info(`LspRangeToRange() — Range Start: ${rangeStart}; Range End: ${rangeEnd}; Start > End? ${rangeStart > rangeEnd}`); 67 | } 68 | if (rangeStart < rangeEnd) { 69 | return new Range(rangeStart, rangeEnd); 70 | } else { 71 | return undefined; 72 | } 73 | // } else if (rangeStart > rangeEnd) { 74 | // return new Range(rangeEnd, rangeStart); 75 | // } else { 76 | // // if they're equal, we'll probably want to change this line only... 77 | // return new Range(rangeStart, rangeEnd + 1) 78 | // } 79 | }; 80 | 81 | // Apply a TextDocumentEdit 82 | // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit 83 | exports.ApplyTextDocumentEdit = (tde) => { 84 | if (tde && tde.textDocument && tde.edits) { 85 | // Obtain a Nova TextEditor for the document 86 | return nova.workspace 87 | .openFile(tde.textDocument.uri) 88 | .then((editor) => { 89 | // exports.ApplyTextEdits(editor, tde.edits); 90 | return exports.ApplyTextEditsRevamped(editor, tde.edits); // making an experiment 91 | }) 92 | .catch((err) => { 93 | console.error('error opening file', err); 94 | }); 95 | } else { 96 | console.info('no edits to apply, it seems'); 97 | } 98 | }; 99 | 100 | // Apply a TextEdit[] 101 | // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit 102 | exports.ApplyTextEdits = (editor, edits) => { 103 | return editor 104 | .edit((tee) => { 105 | edits.reverse().forEach((e) => { 106 | var r0 = exports.LspRangeToRange(editor.document, e.range); 107 | var r1 = new Range(r0.start, r0.end); 108 | tee.replace(r1, e.newText); 109 | }); 110 | }) 111 | .then(() => { 112 | console.info(`${edits.length} changes applied to ${editor.document.path}`); 113 | }); 114 | } 115 | 116 | // NovaPositionFromLSPRange calculates the position relative to LSP (line; character). 117 | // Conceptually similar to LspRangeToRange, but with a different purpose (see ApplyTextEditsRevamped). 118 | // Note: this will very likely blow up since calculations assume UTF-16 (don't you hate Microsoft?) 119 | // (gwyneth 20210406) 120 | exports.NovaPositionsFromLSPRangeElement = function(document, lspLine, lspCharacter) { 121 | const fullContents = document.getTextInRange(new Range(0, document.length)); 122 | let position = 0; 123 | let chars = 0; 124 | const lines = fullContents.split(document.eol); 125 | for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { 126 | const lineLength = lines[lineIndex].length + document.eol.length; 127 | if (lspLine === lineIndex) { 128 | position = chars + lspCharacter; 129 | // break; // we can save a few cycles 130 | return position; // get out of the loop as early as possible 131 | } 132 | chars += lineLength; 133 | } 134 | /* if (nova.inDevMode()) { 135 | console.info(`NovaPositionsFromLSPRangeElement() — LSP Line: ${lspLine}; LSP Column: ${lspCharacter}; Nova Position: ${position}`); 136 | }*/ 137 | return position; 138 | } 139 | 140 | // ApplyTextEditsRevamped calculates if a bit of formatted has to be inserted, replaced, or removed. 141 | // Using ApplyTextEdits will just work for inserting formatted text; but we need a bit more logic in our case 142 | // See also https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-17.md#textEdit to understand how insert/replace/remove is signalled by the LSP (gwyneth 20210406) 143 | exports.ApplyTextEditsRevamped = (editor, edits) => { 144 | return editor.edit((tee) => { // tee - text editor edit (that's how Panic calls it!) 145 | edits.slice().reverse().forEach((e) => { // stupid, but gopls sends these in *reverse* order!! (gwyneth 20210407) 146 | // very, very inefficient for now, but we will improve later using just one loop (gwyneth 20210406) 147 | var startPosition = exports.NovaPositionsFromLSPRangeElement(editor.document, e.range.start.line, e.range.start.character); 148 | var endPosition = exports.NovaPositionsFromLSPRangeElement(editor.document, e.range.end.line, e.range.end.character); 149 | 150 | if (e.newText == null || e.newText == undefined || e.newText == "") { // this means we're going to _delete_ the characters in the range, and that the range must be valid 151 | var deletedRange = new Range(startPosition, endPosition -1); 152 | tee.delete(deletedRange); 153 | console.info(`Deleting text from (${e.range.start.line},${e.range.start.character}) to (${e.range.end.line},${e.range.end.character}) [${startPosition}-${endPosition}]`); 154 | } else if (startPosition == endPosition) { // this means insert a new range 155 | tee.insert(startPosition, e.newText); 156 | console.info(`Inserting «${e.newText}» at (${e.range.start.line},${e.range.start.character}) [${startPosition}]`); 157 | } else if (startPosition < endPosiiton) { 158 | var replacedRange = new Range(startPosition, endPosition -1); 159 | tee.replace(replacedRange, e.newText); 160 | console.info(`Replacing from (${e.range.start.line},${e.range.start.character}) to (${e.range.end.line},${e.range.end.character}) [${startPosition}-${endPosition}] with «${e.newText}»`); 161 | } else { 162 | console.error(`Something bad happened, we should have never reached this spot! We got LSP range: (${e.range.start.line},${e.range.start.character}) to (${e.range.end.line},${e.range.end.character}), Nova Range: [${startPosition}-${endPosition}], text: «${e.newText}»`); 163 | } 164 | }); 165 | }) 166 | .then(() => { 167 | console.info(`${edits.length} changes applied to ${editor.document.path}`); 168 | }); 169 | 170 | } 171 | -------------------------------------------------------------------------------- /Completions/Go.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | go, go *:not(string,string *,comment,variable,regex,regex *) 6 | go.root-variables 7 | go.root-methods 8 | go.constants 9 | (?<!\.)\b[a-zA-Z]* 10 | 11 | 12 | 13 | go, go *:not(string,string *,comment,regex,regex *) 14 | go.global-properties 15 | \.([a-zA-Z]*) 16 | 17 | 18 | 19 | go, go *:not(string,string *,comment,regex,regex *) 20 | go.constructors 21 | \bnew\s+([a-zA-Z]*) 22 | 23 | 24 | 25 | go, go *:not(string,string *,comment,regex,regex *) 26 | go.action.properties 27 | \baction\.(\w*) 28 | 29 | 30 | go, go *:not(string,string *,comment,regex,regex *) 31 | go.context.properties 32 | \bcontext\.(\w*) 33 | 34 | 35 | go, go *:not(string,string *,comment,regex,regex *) 36 | go.lineStorage.properties 37 | \blineStorage\.(\w*) 38 | 39 | 40 | go, go *:not(string,string *,comment,regex,regex *) 41 | go.syntaxTree.properties 42 | \bsyntaxTree\.(\w*) 43 | 44 | 45 | go, go *:not(string,string *,comment,regex,regex *) 46 | go.itemizer.properties 47 | \bitemizer\.(\w*) 48 | 49 | 50 | go, go *:not(string,string *,comment,regex,regex *) 51 | go.textPreferences.properties 52 | \btextPreferences\.(\w*) 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | (;)|[^;] 62 | (?1::;) 63 | 64 | 65 | 66 | 67 | 68 | 69 | ([^\n\r]?)|[\n\r] 70 | (?1:: ${1:condition}:) 71 | 72 | 73 | 74 | 75 | 76 | 77 | (;)|[^;] 78 | (?1::;) 79 | 80 | 81 | 82 | 83 | 84 | 85 | (:)|[^:] 86 | (?1:::) 87 | 88 | 89 | 90 | 91 | 92 | 93 | (\s*\{)|\s*[^{]|[^\s{] 94 | (?1:: { 95 | $0 96 | }) 97 | 98 | 99 | 100 | 101 | 102 | 103 | (\s*\()|\s*[^(]|[^\s(] 104 | (?1:: (${1:${2:var i = 0}; ${3:i < count}; ${4:i++}}\) { 105 | $0 106 | }) 107 | 108 | 109 | 110 | 111 | 112 | 113 | (\s*\()|(\s*\{)|\s*[^(]|[^\s(] 114 | (?1::(?2: ($0\): ($1\) { 115 | $0 116 | })) 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | (\s*\()|\s*[^(]|[^\s(] 125 | (?1:: ($1\) { 126 | $0 127 | }) 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | (\s*\()|(\s*\{)|\s*[^(]|[^\s(] 138 | (?1::(?2: ($0\): ($1\) { 139 | $0 140 | })) 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | (\s*\(|\s+[a-zA-Z_$])|\s*[^(a-zA-Z_$]|[^\s(] 150 | (?1:: ${1:name}($2\) {$3}) 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | (\()|[^(] 179 | (?1::($1\)) 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | (\()|[^(] 227 | (?1::(${1:string}\)) 228 | 229 | 230 | 231 | 232 | 233 | (\()|[^(] 234 | (?1::(${1:sliceType}, ${2:length}, ${3:capacity}\)) 235 | 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Version 0.4.3 2 | - Several new improvements on syntax checking; a lot more is being correctly highlighted (but there is even more that isn't; see [README.md](README.md)). 3 | - Adding the @all-contributors GitHub bot to give people a bit more credit. They deserve it! 4 | - Edited some of the (outdated) information on the README. 5 | - Added a special class on my sister project, the Nord theme extension, to provide highlighting for delimiters. 6 | - More crazy tests on `basictest.go` to catch common syntax highlighting errors (there are many). 7 | - Added a funding button, let's see if it works! 8 | - TODO(gwyneth): Try to understand why the imports aren't properly formatted by `gopls`, even if the rest is... 9 | 10 | ## Version 0.4.2 11 | 12 | - Thanks to @logan's changes on correctly implementing Markdown hover tags! 13 | 14 | ## Version 0.4.1 15 | 16 | - Added checkbox on preferences to use https://staticcheck.io/ to do additional code analysis. 17 | 18 | ## Version 0.4.0 19 | 20 | - Nova 5.1 is out and it supports Language Servers much better! Enjoy the quasi-IDE environment! 21 | - Added support for editing `go.mod` files. Note: If you've installed [VLC](https://www.videolan.org/vlc/), `.mod` files are thought to be audio files, thus they're not easily opened with Nova (added `Tests/go.mod.sample` to test it out). 22 | - *Big* cleaning up of the syntax definition file; all regular expressions have been tested, one by one, and fixed in uncountable cases. Even capturing complex numbers works! Much better syntax highlighting. Incidentally, issue [_#1_](https://github.com/GwynethLlewelyn/Go.novaextension/issues/1) got fixed, after 7 months... 23 | - The **Editor > Go** menu options for text formatting and reorganising imports work about 80% of the cases. They are now interfacing correctly with `gopls` and retrieving proper replacement information (who'd think that Google would send all updates _in reverse order_?!). So, no need to run any additional external commands for those operations; `gopls` is _supposed_ to do all the work from now on. 24 | - Sadly, the option to format/optimise imports on _saving_ is **not** functional. There is an **experimental** checkbox for it on the preferences, but **DO. NOT. CHECK. IT.**. It will _literally_ destroy your files when saving them. Basically, it runs the formatter twice, for some unfathomable reason, and I couldn't find a way to prevent that. 25 | 26 | ### To-do: 27 | - Add a checkbox to get your code additionally validated by https://staticcheck.io/. It's easy enough to set up — it's fully integrated by Google in `gopls` itself! 28 | - Make the _new_ code to convert from Nova ranges into LSP ranges a bit more efficient; or pester Panic to do that conversion available via the JS API (after all, they use it internally!). Note that this is mostly a proof-of-concept version (it's still alpha code, remember? 😉) just to fix an annoying bug that comes from wrong assumptions about `gopls` (other Language Servers seem to work... all have their own quirks). 29 | - Figure out _why_ `gopls` is running *twice* when saving (thus thrashing everything), although just once when called from the menu options. I've clearly hit a personal limit; this is beyond my ability and knowledge to understand at the moment. 30 | - Figure out how to install VLC and still have Nova opening `go.mod` files without thinking they're video files! 31 | 32 | ## Version 0.3.5 33 | 34 | - Basically just bumping the version to remove the warning about not being possible to update this extension via the Nova Extension Library. Panic fixed everything! 35 | - Amazingly, the reorganisation of import files, via `gopls`, seems to work! 😲 Try to mouse-select your imports and click on **Editor > Go > Organize Imports** — this should do *something* 36 | - The extension still crashes if it is deactivated/reactivated; also, it now might get a bit confused when figuring out if the `gopls` server is running or not. Sometimes it requires a reset (via the check box on Preferences). 37 | 38 | ## Version 0.3.4 39 | 40 | - Many of the crashes are related to objects which haven't been correctly initialised, or, worse, released (google for `KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED`); this release attempts to fix some of those errors 41 | - Added more `try{...}catch` constructs in order to see some (possibly hidden) errors _before_ Nova crashes 42 | - Slightly changed a few functions to better deal with the differences in handling extensions with a Language Server, compared to earlier Nova versions 43 | 44 | ## Version 0.3.3 45 | 46 | - Finally figured out how to turn hover Markdown off! Next step: figuring out how to _fix_ it... 47 | - Banner logo is back, I thought it made a difference when downloading the extension, but no: the problem lies elsewhere on Nova's servers (as of writing, they're on it and trying to fix things) 48 | - Fixed a few extra things, again, to comply with the extension template 49 | - Tried to incorporate @jfieber's changes (a few options now appear on the Editor menu, but they don't do much; I know that they're _working_, since they _do_ get `gopls` to write things on the log) 50 | - Updated license to display contributors (Nova won't show it, though) 51 | - Updated README with some extra thanks and a warning that downloading this extension/updating it may fail due to some as-yet-unsolved issues with Panic's Nova Extension Library server (this plugin is not the only one being affected) 52 | 53 | ## Version 0.3.2 54 | 55 | - Changed some of the code to comply better with the latest extension template included with Nova 4.3 — this may, or may not, fix some crashing issues (because things were called differently before) 56 | - Force `gopls` to use plain text instead of Markdown, on a single line; it's not as nice, but at least it works 57 | - Apparently there was some issue with Nova's library extension server earlier on, and that's why the earlier version failed, it should get fixed sooner or later 58 | 59 | ## Version 0.3.1 60 | 61 | - Bumping the version because something went wrong with the upload 62 | 63 | ## Version 0.3.0 64 | 65 | - Major rewriting of the code base, mostly thanks to the generous work provided by @jfieber and @seripap. Thanks guys! 66 | - LSP interfacing with `gopls` now works! But don't expect miracles, we haven't still figured out all of it. Use `brew install gopls`. 67 | - A few extension preferences were added by @jfieber (namely, turning LSP on and off, etc.); also, for development purposes, `gopls` will write some (cryptic) logs under `/tmp/gopls.log` 68 | - Added more references to licenses; we are now including open-source code from Microsoft (I never though I'd ever write this in my lifetime! 😳🤓) 69 | - Added more blahblahblah to the [README.md](README.md) (and a few markdown tricks!) 70 | - New logo (ok, this is trivial, but I'm trying to keep up with Panic's re-styling! 😅) 71 | - To-do: figure out why `gopls` sends raw Markdown that Nova doesn't seem to understand 72 | - To-do: understand why the extension crashes so often (at least in dev mode); it's possible that some cleanup code is missing and/or broken 73 | - Tested under Nova 4.3 74 | 75 | ## Version 0.2.1 76 | 77 | - Small JSON change from 'vendor' to 'organization' according to the new specs for the Nova Beta 1.0b18 (195066) 78 | - Tried to add `gopls` again, but couldn't 79 | 80 | ## Version 0.2.0 81 | 82 | - Added gazillions of changes, based on several different templates and the manuals of a competitor editor which uses similar syntax (which was originally based on the templates for Coda!) 83 | - While this produces slightly better matching, there are tons of rules that never get activated but I don't know why 84 | - Added a Smarty-like parser for Go Templates (it's basically the same concept with some tiny, Go-specific changes) 85 | - Added some test files, please ignore them, they're not meant to be 'working code' (nor even valid one) 86 | - Had to remove `gopls` because it's too big! You can download it from https://github.com/golang/tools/tree/master/gopls 87 | 88 | ## Version 0.1.6 (never released) 89 | 90 | - With the new Nova Beta update to 1.0b17 (Build 190148) it looks like the executable for `gopls` lost its executable flag; if that did make a difference or not is beyond me, but I recompiled `gopls` again, with newer libraries. 91 | - When clicking on the syntax inspector button (at the bottom of each pane, the tiny 'target' icon which is to the left of the 'current symbol'), now 'something' happens when randomly clicking on Go code (i.e. there is a modal popup box that shows some information). If that's the desired behaviour or not... I have no idea. 92 | 93 | ## Version 0.1.5 94 | 95 | - Make `.mod` files (e.g. `go.mod`) be part of the extensions, or else they will be seen as music files 96 | 97 | ## Version 0.1.4 98 | 99 | Cleaning up the logs when instance is deactivated. 100 | 101 | ## Version 0.1.3 102 | 103 | - Bumped version again 104 | - Some more experiments on the test file `basictest.go` 105 | 106 | ## Version 0.1.2 107 | 108 | - Slight bug on `main.js` (missing bracket) 109 | 110 | ## Version 0.1.1 111 | 112 | - Version 0.1.0 was successfully uploaded to the Extensions Library!! 113 | - Go LSP seems not to be working at all 114 | - Lots of errors in syntax highlighting (e.g. variable declaration) 115 | 116 | ## Version 0.1.0 117 | 118 | - After checking the many XML files, I found three minor bugs, and now the syntax highlighting not only works, but it shows up as a 'valid' language on all the places that it ought to show up! 119 | - Apparently, you cannot have any images under the `Images/` folder, or uploading to the Extension Library does _not_ work 120 | - Still working to fix the connection to the Go LPS (it's not being launched right now, but I have some ideas to fix it...) 121 | 122 | ## Version 0.0.2 123 | 124 | - Syntax definition XML based on Nova JavaScript, using definitions from the old Coda 2 Go mode 125 | - Tried to add Go LPS support 126 | - Added the logo and a few things 127 | 128 | ## Version 0.0.1 129 | 130 | Initial release — based on the original Coda 2 Go mode 131 | -------------------------------------------------------------------------------- /Scripts/main.js: -------------------------------------------------------------------------------- 1 | var lsp = require('lsp.js'); 2 | var langserver = null; 3 | 4 | exports.activate = function () { 5 | // Do work when the extension is activated 6 | langserver = new GoLanguageServer(); 7 | }; 8 | 9 | exports.deactivate = function () { 10 | // Clean up state before the extension is deactivated 11 | if (langserver) { 12 | langserver.deactivate(); // conforming to newer Nova templates 13 | langserver = null; 14 | } 15 | // shouldn't we remove /tmp/gopls.log? (gwyneth 20210129) 16 | nova.fs.remove('/tmp/gopls.log'); // if it doesn't exist, does nothing (20210130) 17 | }; 18 | 19 | class GoLanguageServer { 20 | constructor() { 21 | // From the new template for extensions using LSP (gwyneth 20210203) 22 | // Observe the configuration setting for the server's location, and restart the server on change 23 | nova.config.observe('go-nova.gopls-path', function(path) { 24 | this.start(path); 25 | }, this); 26 | 27 | // Handle preference change for enable/disable. 28 | nova.config.onDidChange( 29 | 'go-nova.enable-gopls', 30 | function (current, previous) { 31 | if (current) { 32 | this.start(); 33 | } else { 34 | this.stop(); 35 | } 36 | }, 37 | this 38 | ); 39 | 40 | // Handle preference change for gopls path. 41 | nova.config.onDidChange( 42 | 'go-nova.gopls-path', 43 | function (current, previous) { 44 | // If the user deletes the value in the preferences and presses 45 | // return or tab, it will revert to the default of 'gopls'. 46 | // But on the way there, we get called once with with current === null 47 | // and again with current === previous, both of which we need to ignore. 48 | if ( 49 | current && 50 | current != previous && 51 | nova.config.get('go-nova.enable-gopls', 'boolean') 52 | ) { 53 | console.info('Restarting gopls due to path change'); 54 | this.stop(); 55 | // Hack: until we can reliably determine when the service is 56 | // actually stopped, pause a few ticks to already running error. 57 | setTimeout(() => { 58 | this.start(); 59 | }, 2000); 60 | } 61 | }, 62 | this 63 | ); 64 | 65 | // Start on load, if the preferences say so. 66 | if (nova.config.get('go-nova.enable-gopls', 'boolean')) { 67 | this.start(); 68 | } 69 | } 70 | 71 | deactivate() { 72 | this.stop(); 73 | } 74 | 75 | start(path) { // seems that it now requires an extra variable... 76 | // Check if gopls is already running; this is acording to the new extension template (gwyneth 20210202) 77 | if (this.languageClient) { 78 | this.languageClient.stop(); 79 | nova.subscriptions.remove(this.languageClient); // redundant, .stop() allegedly does this, but that's what we've got on the new template... (gwyneth 20210202) 80 | } 81 | 82 | // Basic server options 83 | var serverOptions = { 84 | path: nova.config.get('go-nova.gopls-path', 'string') || 'gopls' || path, 85 | args: ['serve'], 86 | }; 87 | 88 | // An absolute path or use the search path? 89 | if (serverOptions.path.charAt(0) !== '/') { 90 | serverOptions.args.unshift(serverOptions.path); 91 | serverOptions.path = '/usr/bin/env'; 92 | } 93 | 94 | if (nova.inDevMode()) { 95 | serverOptions.args = serverOptions.args.concat([ 96 | '-rpc.trace', 97 | '-logfile', 98 | '/tmp/gopls.log', 99 | ]); 100 | console.info('gopls server options:', JSON.stringify(serverOptions)); 101 | } 102 | 103 | // Recent versions of Nova can also send initializationOptions. The syntax 104 | // is not obvious, because Microsoft and Google use so confusing notations 105 | // which are mutually incomprehensible (MS uses TypeScript, Google uses Go). 106 | // See https://github.com/golang/tools/blob/master/gopls/doc/settings.md 107 | // (gwyneth 20210131) 108 | var clientOptions = { 109 | syntaxes: ['go'], 110 | initializationOptions: { 111 | // "hoverKind": "SingleLine", // I know that "SingleLine" works — other options seem to _always_ trigger Markdown (gwyneth 20210202) for the information, which somehow Nova dislikes and does not render (gwyneth 20210407) 112 | "hoverKind": "SynopsisDocumentation", // available since Nova 6...? (gwyneth 20210422) 113 | "staticcheck": nova.config.get('go-nova.use-staticcheck', 'boolean'), // using staticcheck.io for further analysis (gwyneth 20210407) 114 | "usePlaceHolders": true // trying out which one works (gwyneth 20210203) 115 | } 116 | }; 117 | 118 | if (nova.inDevMode()) { 119 | console.info("gopls client options:", JSON.stringify(clientOptions)); 120 | } 121 | 122 | var client = new LanguageClient( 123 | 'gopls', 124 | 'Go Language Server', 125 | serverOptions, 126 | clientOptions 127 | ); 128 | 129 | try { 130 | // Start the client 131 | client.start(); 132 | 133 | // Add the client to the subscriptions to be cleaned up 134 | nova.subscriptions.add(client); 135 | this.languageClient = client; 136 | } catch (err) { 137 | // If the .start() method throws, it's likely because the path to the language server is invalid 138 | console.error("Couldn't start the gopls server; please check path. Error was: ", err); 139 | } 140 | 141 | // Code by @apexskier introduced by @jfieber 142 | // Registers the commands that can be invoked from the menu as well as the format-on-save 143 | try { 144 | this.commandJump = nova.commands.register('go.jumpToDefinition', jumpToDefinition); 145 | this.commandOrganizeImports = nova.commands.register('go.organizeImports', organizeImports); 146 | this.commandFormatFile = nova.commands.register('go.formatFile', formatFile); 147 | // The code below comes from @jfieber (slightly adapted) (gwyneth 20210406) 148 | this.formatOnSave = nova.workspace.onDidAddTextEditor((editor) => { 149 | editor.onDidSave(() => { 150 | console.log('Saved complete'); 151 | }); 152 | editor.onWillSave((editor) => { 153 | if (editor.document.syntax === 'go') { 154 | if (nova.config.get('go-nova.format-on-save', 'boolean')) { 155 | console.info('Entering FormatOnSave for "' + editor.document.uri + '"...'); 156 | try { 157 | // nova.commands.invoke("go.formatFile", editor); // this is how @apexskier calls the function (20210408) 158 | formatFile(editor); 159 | } catch(err) { 160 | console.error("Re-formatting failed miserably"); 161 | } 162 | } 163 | } 164 | }, this); 165 | }, this); 166 | 167 | } catch(err) { 168 | console.error("Could not register editor commands: ", err); 169 | } 170 | } 171 | 172 | // According to the revised Nova documentation, we should only get a stop() iff the server is still 173 | // running; but we nevertheless keep the old code around anyway (gwyneth 20210406) 174 | stop() { 175 | if (this.languageClient) { 176 | try { 177 | if (this.commandJump && isDisposable(this.commandJump)) { 178 | this.commandJump.dispose(); 179 | } 180 | if (this.commandOrganizeImports && isDisposable(this.commandOrganizeImports)) { 181 | this.commandOrganizeImports.dispose(); 182 | } 183 | if (this.commandFormatFile && isDisposable(this.commandFormatFile)) { 184 | this.commandFormatFile.dispose(); 185 | } 186 | if (this.formatOnSave && isDisposable(this.formatOnSave)) { 187 | this.formatOnSave.dispose(); 188 | } 189 | } catch(err) { 190 | console.error("While stopping, disposing the editor commands failed: ", err); 191 | } 192 | try { 193 | this.languageClient.stop(); 194 | nova.subscriptions.remove(this.languageClient); 195 | this.languageClient = null; 196 | } catch (err) { 197 | console.error("Could not stop languageClient and/or remove it from subscriptions: ", err); 198 | } 199 | } else { 200 | console.error("For some reason, Nova tried to stop a languageClient that wasn't running."); 201 | } 202 | } 203 | 204 | client() { 205 | return this.languageClient; 206 | } 207 | } 208 | 209 | // Code by @apexskier introduced by @jfieber 210 | // This may use some code developed by Microsoft — see [Microsoft Public License (MS-PL)](https://opensource.org/licenses/MS-PL) 211 | function organizeImports(editor) { 212 | if (langserver && langserver.client()) { 213 | var cmd = 'textDocument/codeAction'; 214 | var cmdArgs = { 215 | textDocument: { 216 | uri: editor.document.uri 217 | }, 218 | range: lsp.RangeToLspRange(editor.document, editor.selectedRange), 219 | context: { diagnostics: [] } 220 | }; 221 | 222 | langserver.client().sendRequest(cmd, cmdArgs).then((response) => { 223 | // console.info(`${cmd} response:`, response); 224 | if (response !== null && response !== undefined) { 225 | response.forEach((action) => { 226 | if (action.kind === "source.organizeImports") { 227 | console.info(`Performing actions for ${action.kind}`); 228 | action.edit.documentChanges.forEach((tde) => { 229 | lsp.ApplyTextDocumentEdit(tde); 230 | }); 231 | } else { 232 | console.info(`Skipping action ${action.kind}`); 233 | } 234 | }); 235 | } 236 | }).catch(function(err) { 237 | console.error(`${cmd} error!:`, err); 238 | }); 239 | } else { 240 | console.error("organizeImports() called, but gopls language server is not running"); 241 | } 242 | } 243 | 244 | function formatFile(editor) { 245 | if (langserver && langserver.client()) { 246 | var cmd = 'textDocument/formatting'; 247 | var cmdArgs = { 248 | textDocument: { 249 | uri: editor.document.uri 250 | }, 251 | options: { // https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-17.md#document-formatting-request--leftwards_arrow_with_hook (gwyneth 20210406) 252 | tabSize: editor.tabLength, 253 | insertSpaces: editor.softTabs != 0 254 | } 255 | }; 256 | if (nova.inDevMode()) { 257 | console.info("formatFile(): cmdArgs is ", JSON.stringify(cmdArgs, undefined, 4)); 258 | } 259 | langserver.client().sendRequest(cmd, cmdArgs).then((response) => { 260 | if (nova.inDevMode()) { 261 | console.info(`formatFile(): '${cmd}' response:`, JSON.stringify(response, undefined, 4)); 262 | } 263 | if (response !== null && response !== undefined && response !== []) { 264 | // lsp.ApplyTextEdits(editor, response); 265 | lsp.ApplyTextEditsRevamped(editor, response); // trying to deal with replace/delete/insert issues (gwyneth 20210406) 266 | } 267 | }).catch(function(err) { 268 | console.error(`formatFile(): ${cmd} error! - `, err); 269 | }); 270 | } else { 271 | console.error("formatFile() called, but gopls language server is not running"); 272 | } 273 | } 274 | 275 | function jumpToDefinition(editor) { 276 | if ( 277 | langserver === null || 278 | langserver.client() === null || 279 | langserver.client() === undefined 280 | ) { 281 | console.info("jumpToDefinition() called, but gopls language server is not running"); 282 | return; 283 | } 284 | var selectedRange = editor.selectedRange 285 | selectedPosition = 286 | (_a = lsp.RangeToLspRange(editor.document, selectedRange)) === null || 287 | _a === void 0 288 | ? void 0 289 | : _a.start 290 | if (!selectedPosition) { 291 | nova.workspace.showWarningMessage( 292 | "Couldn't figure out what you've selected." 293 | ); 294 | return; 295 | } 296 | var params = { 297 | textDocument: { 298 | uri: editor.document.uri, 299 | }, 300 | position: selectedPosition, 301 | } 302 | var jump = langserver.client().sendRequest('textDocument/definition', params) 303 | // {"uri":"file:///opt/brew/Cellar/go@1.14/1.14.7/libexec/src/fmt/print.go","range":{"start":{"line":272,"character":5},"end":{"line":272,"character":12}}} 304 | 305 | jump.then(function (to) { 306 | if (to !== null) { 307 | if (to.length > 0) { 308 | var target = to[0] 309 | console.info('Jumping', JSON.stringify(to[0])) 310 | nova.workspace 311 | .openFile(target.uri) 312 | .then(function (targetEditor) { 313 | // When Nova first opens a file, the callback gets an undefined editor, 314 | // which is most likely a bug. Usually works the second time. 315 | if (targetEditor === undefined) { 316 | console.error('Failed to get TextEditor, will retry') 317 | nova.workspace 318 | .openFile(target.uri) 319 | .then(function (targetEditor) { 320 | targetEditor.selectedRange = lsp.LspRangeToRange( 321 | targetEditor.document, 322 | target.range 323 | ) 324 | targetEditor.scrollToCursorPosition() 325 | }) 326 | .catch(function (err) { 327 | console.error( 328 | 'Failed to get text editor on the second try', 329 | err 330 | ) 331 | }) 332 | } else { 333 | targetEditor.selectedRange = lsp.LspRangeToRange( 334 | targetEditor.document, 335 | target.range 336 | ) 337 | targetEditor.scrollToCursorPosition() 338 | } 339 | }) 340 | .catch(function (err) { 341 | console.info('Failed in the jump', err); 342 | }) 343 | } 344 | } 345 | }) 346 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Go Nova Extension Logo](https://github.com/GwynethLlewelyn/Go.novaextension/blob/master/Images/extension/Go-Nova-Banner.png?raw=true) 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | # Go Language Definition for Nova 7 | 8 | An ongoing attempt to build a Go language definition for the [Panic Nova](https://panic.com/nova) editor, using the Language Server Protocol (LSP) with Google's official `gopls` language server for Go. 9 | 10 | **Note:** v0.4.3 is still an **alpha** version with working syntax highlighting and extra goodies from using the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/), but it is plagued with some unstability issues, often leading to a crash. See below for some guidelines. 11 | 12 | [@jfieber](https://github.com/jfieber) added a 'Go' menu from which some functionality can be selected; in many cases, it will attempt to do a re-formatting according to Go's best practices, as well as organise imports. This is not working 100% of the time, though (and we still don't know why). 13 | 14 | Worst case scenario: if _nothing_ here works for you, you might try to use Spicer Matthews' own [GoTools](nova://extension?id=cloudmanic.GoTools "This link will open only in Nova") extension. The syntax highlighting should be similar — and that extension should _not_ crash! 15 | 16 | ## Installation 17 | 18 | Once activated, files ending in `*.go` should automatically be recognised (and formatted) as Go language files. Similarly, `*.tmpl` [Go template files](https://golang.google.cn/pkg/html/template/) will also be recognised[1](#f1), and from version 0.4.0 onwards, even `go.mod` gets its own syntax highlighting. 19 | 20 | Additional Go specific features are available by installing the [Go Language Server](https://github.com/golang/tools/blob/master/gopls/README.md), `gopls`. This will turn Nova into a quasi-IDE for Go! 21 | 22 | If you use [Homebrew](https://brew.sh/) to install your packages, all you need is to type: 23 | 24 | `brew install gopls` 25 | 26 | If not, you can install it as described [here](https://github.com/golang/tools/blob/master/gopls/doc/user.md#installation). 27 | 28 | Then tick the *Enable Language Server* checkbox in the Preferences for this extension. If `gopls` is (correctly) installed in your search `PATH`, the extension should find it. If it is elsewhere, set that where in the Preferences for this extension as well. Note that Nova's language server support and `gopls` are both new and evolving. Many things may _not_ work quite right yet. 29 | 30 | When checking for syntax errors, `gopls` can optionally use https://staticcheck.io/ for additionally analysis; there is a checkbox on Preferences to allow the extra checking. 31 | 32 | **WARNING:** (aye, again) If you click on *Format/Organise Imports when saving file* to get `gopls` to automatically reformat your code when saving, be warned: it _really_ does corrupt the files! I'm _not_ joking. The option is there just because I'm hoping to try it out until I find a way to fix the issue. 33 | 34 | More information on the capabilities of `gopls` as well as its design/implementation considerations can be found [on GitHub](https://github.com/golang/tools/blob/master/gopls/doc/design/design.md). As Nova gets better and better integration with Language Servers, and as Google also improves `gopls` to be more compliant with Microsoft's LSP definition, a lot of functionality will appear 'automagically' by simply upgrading Nova or `gopls`. 35 | 36 | ## Disclaimers 37 | 38 | I'm _still_ a bit clueless about how the syntax highlighting engine/parser actually parses the language files (although some things are starting to make more sense). There is _very little_ 'official' documentation; however, on the site for an editor made by a competitor, it looks like they have used something very similar, and — allegedly! — based on the original Coda syntax (not Coda 2!). Apparently, Nova uses a variant of the same parser 'family'. 39 | 40 | This version includes a `Go.xml` Syntax template which was cobbled together out of a _lot_ of sources, namely, the Coda 2 Go language definition files; the Nova (included) language files for PHP, TypeScript (because Go is also strongly typed), JavaScript, and even C++; I've made extensive use of https://regex101.com/ to check the correctness of most (if not all) regular expressions needed for the syntax highlighting; and I'm also very quite thankful for the (incomplete) work made by [@ambelovsky](https://github.com/ambelovsky/espresso-golang) (on GitHub), when adapting the old Coda syntax for the editor from the competition. Several of his comments have been copied and incorporated. His work was sadly not completed, still had a lot of errors (basically he used the template for JavaScript), and, at the date of writing, was abandoned nine years ago. Nevertheless, it had lots of very interesting structures to parse the Go language (while leaving several others unimplemented). While strongly _inspired_ by his work, this is not merely a copy & paste — many adaptations were required to get some of the functionality to actually work. A lot still doesn't (it gets silently ignored) and I still haven't figured out how to deal with them... 41 | 42 | Additionally, I've included a Syntax template for Go Templates. It's almost exactly the same as the syntax for Smarty templates (which I have been using) with some tiny changes, which I hope to have correctly implemented. 43 | 44 | The new, incuded syntax highlighter for `go.mod` files was mostly an experiment. It works quite well, though, since the language definition for that is so simple. 45 | 46 | Although the current version includes a Completions file, I don't see any kind of completion happening (except for closing braces). I've tried to figure out how the syntax of the Completions file works, but it's even more obscure (to me) than the actual Syntax file. The two are also possibly related — through common identifiers — but I fail to understand exactly how the two 'play' together. I've gotten access to a few more resources explaining this format, so maybe I'll give it another try. 47 | 48 | Also, Nova — unlike Coda — allows extensions to use the [Language Server Protocol](https://langserver.org/) (like their closest competitors do), a Microsoft-promoted effort enabling a '*write once, reuse often*' philosophy for writers of syntax checkers. In other words, the hard work is put into creating a _functioning_ LSP 'server' (basically an application that reads a file in a specific language, or parts of a file, and figures out if it has any syntax errors) by the community of syntax checkers. _Then_ editor plugins (of all kinds, not only desktop apps) can interface with such a server in order to get syntax checking. In theory, it's a very easy way to quickly expand the ability for a code editor to accept gazillions of languages without requiring the developers to spend days and nights coding as many syntax checkers as possible. With new languages coming up all the time, many becoming fashionable for a few years and disappearing shortly afterwards, this method ensures that editor developers are not wasting their precious time. It also means that updating syntax checkers for upcoming new versions of a specific language will not require any coding — just upgrade the LSP server. And, finally, it also means that _all_ code editors will check syntax in the _same, predictable_ way (and also that _all_ will get upgraded to the latest version of the syntax almost immediately), which means that, if you switch editors, the 'new' editor will _already_ support the latest version of your favourite programming language _and_ syntax checking will work in pretty much the same way... 49 | 50 | Therefore, this extension can optionally use the official (Google-supported) [Go Language Server](https://github.com/golang/tools/blob/master/gopls/README.md) if you install it as described in the Installation section above. Thanks to recent improvements in Nova, it's now almost fully functional. Enjoy 😌 51 | 52 | The LSP specification is still very quirky. Microsoft developed the LSP specifically for Visual Studio Code, their free, open-source, cross-platform editor, thus allowing non-Microsoft-specific languages to be as easily integrated with their editor. However, the Microsoft specifications are *very* Microsoft-centric, and the Google team behind `gopls` grumbles and complains about several ambiguous descriptions in the protocol, and the choices they've made to implement the (complex) specifications. Sadly, though, those specifications are *very* Google-centric (notice the pattern?) and they don't match easily with the Microsoft ones. And on top of all that, we have to deal with Panic's own implementation of LSP support — which is (at the time of writing!) a bit obscure, a bit opaque, and not exactly super-well-documented (namely, at least for me, it's not obvious what Nova does on its own and what the extension developer has to do). We have to take hints from the very few others who travelled the same road and try to figure out how they've done it. 53 | 54 | Note that Nova logs many interactions with the language server in the Extension Console, and if you run this extension in "developer mode" (see the *Extension Development* item in Nova's *General* preferences) `gopls` will write logs to `/tmp/gopls.log` but these can be quite a bit cryptic. 55 | 56 | In conclusion: all of the above is still very much a _work in progress_ — or rather, a _lot_ of work in progress. There is far less functionality which actually does anything than lots of files with rules that are _supposed_ to do _something_ but... don't. Therefore, _caveat utilitor_. 57 | 58 | Suggestions and bug reports are more than welcome, but please take into account that I'm new to all of this, and might not be able to even _understand_ most of your issues, much less _fix_ them! But I'm learning... 59 | 60 | ## Well-known bugs 61 | 62 | ### Syntax Checker bugs 63 | 64 | 1. On function definitions, the return values are not properly formatted (not even recognised by Nova) 65 | 2. Similarly, the `return` keyword will confuse the formatting of the ensuing expressions 66 | 3. On function definitions, arguments such as `(a,b integer)` _will_ be correctly formatted, but they are on the completely wrong scope (compare it with writing `(a integer, b integer)` instead) 67 | 4. Type declaration is still a work-in-progress; it's now foldable, but doesn't work correctly (getting it right is tough!) 68 | 5. Even variable declaration is... sketchy, at best. Some instances of it work; most don't 69 | 6. No type casting done (yet) 70 | 7. `make` and `append` aren't done yet 71 | 72 | ### Go Language Server bugs 73 | 74 | 1. Right now, the one issue that baffles me most is why the imports formatter does not work properly (i.e. the equivalent functionality to `goimports` which is allegedly built-in into the `gopls` Language Server)! It still has a very serious bug when figuring out what exactly to delete and shuffle around. Don't try it out without saving your files properly! 75 | 2. As said before, do **NOT** turn on the automatic formatting when saving! Until this issue isn't fixed, that option is essentially there only for the purpose of allowing others to do some testing. It's _not_ meant for anything else! 76 | 3. The `Go` menu (either from the top bar or by right-clicking on the text) runs the formatter most of the time, without crashing. Sometimes it does nothing; sometimes you have to select the whole range you wish to format in order to get it working. This is still a bit unpredictable, although I can't understand why it doesn't work _some_ times, while in _most_ cases, it has no issue whatsoever (even on the same, unchanged code!). 77 | 4. If you're plagued with extension crashes, just _un_check the *Enable Language Server* checkbox on the Preferences for this extension. You will still get Go syntax highlighting (and some auto-completion), but the additional goodies provided by LSP will be turned off. 78 | 5. There are a few hooks allowing you to *theoretically* run some post-formatting tools to comply with Google's style guidelines for Go, as well as a way to check that all imports are properly referenced, etc. With this version, there is no documentation yet for *how* to activate those extra features, but hopefully this will be addressed in the future... eventually. 79 | 80 | ## My GPG Fingerprint 81 | 82 | In case you need it to send me encrypted emails: 83 | 84 | > CE8A 6006 B611 850F 1275 72BA D93E AA3D C4B3 E1CB 85 | 86 | --- 87 | 88 | 1 I based that parser on the [PHP Smarty templates](https://www.smarty.net/) — Go's own template syntax is similar.[↩](#a1) 89 | 90 | ## Contributors ✨ 91 | 92 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 |

Daniel Seripap

💻

Matt Mc

🤔 💬

John Fieber

💻 🤔 📖

Cameron Little

🤔
105 | 106 | 107 | 108 | 109 | 110 | 111 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 112 | -------------------------------------------------------------------------------- /Syntaxes/Go.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Go 5 | compiled 6 | go 7 | go 8 | 9 | 10 | 11 | 12 | go 13 | 14 | 15 | 16 | 17 | (\{[^}\"']*$)|(\[[^\]\"']*$)|(\([^)\"']*$) 18 | 19 | 20 | ^\s*(\s*\/\*.*\*\/\s*)*[\}\]\)\\] 21 | 22 | 23 | 24 | 25 | 26 | // 27 | 28 | 29 | 30 | /* 31 | 32 | 33 | */ 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | (\/\/)(.*)$ 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | \/\* 98 | 99 | 100 | 101 | \*\/ 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | \{ 114 | 115 | 116 | 117 | \} 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | (func)\s+(main|init) 137 | 138 | 139 | 140 | 141 | (?<=\}) 142 | 143 | 144 | 145 | (?=\b(?:func|if|else|while|for|range)\b) 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | (func)\s+([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*) 158 | 159 | 160 | 161 | 162 | (?<=\}) 163 | 164 | 165 | 166 | (?=\b(?:func|if|else|while|for|range)\b) 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | \b(type)\s+([a-zA-ZÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+(struct)\b 182 | 183 | 184 | 185 | 186 | 187 | 188 | (?<=\}) 189 | 190 | 191 | 192 | (?=\b(?:func|if|else|while|for|range)\b) 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | (func)\s+(\()([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+((\*?)[A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s*(\))\s+([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*) 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | (?<=\}) 216 | 217 | 218 | 219 | \(?=\b(?:func|if|else|while|for|range)\b\) 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | (func)(?=\s*\() 234 | 235 | 236 | 237 | (?<=\}) 238 | 239 | 240 | 241 | (?=\b(?:func|if|else|while|for|range)\b) 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | \( 258 | 259 | 260 | 261 | \) 262 | 263 | 264 | 265 | 266 | (?=\b(?:func|if|else|while|for)\b) 267 | 268 | 269 | 270 | 271 | , 272 | 273 | 274 | 275 | 276 | (\.\.\.)\b([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b 277 | 278 | 279 | 280 | 281 | 282 | (?<!\=)\b([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+(\*?)(\[\d*\])?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | [!\(]\b(\*?)(\[\d*\])([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b[!\(] 299 | 300 | 301 | 302 | 303 | 304 | 305 | \( 306 | 307 | 308 | 309 | \) 310 | 311 | 312 | 313 | 314 | (?=\b(?:func|if|else|while|for)\b) 315 | 316 | 317 | 318 | , 319 | 320 | 321 | 322 | 323 | (?<!\=)\b([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+(\*?)(\[\d*\])([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | \{ 343 | 344 | 345 | 346 | \} 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | break 361 | case 362 | chan 363 | const 364 | continue 365 | default 366 | defer 367 | else 368 | fallthrough 369 | for 370 | func 371 | go 372 | goto 373 | if 374 | import 375 | interface 376 | map 377 | package 378 | range 379 | return 380 | select 381 | struct 382 | switch 383 | type 384 | var 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | nil 395 | 396 | 397 | 398 | 399 | true 400 | false 401 | 402 | 403 | 404 | 405 | iota 406 | 407 | 408 | 409 | \b0(x|X)[a-fA-F0-9]+\b 410 | 411 | 412 | \b0[0-7]+\b 413 | 414 | 415 | 416 | (-?)((\b\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)[ \t]*([+\-])[ \t]*((\b\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)([iI])|(-?)((\b\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)([iI]) 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | (-?)((\b\d+\.\d*|\.\d+)([eE][-+]?\d+)?) 432 | 433 | 434 | 435 | 436 | 437 | \b-?\d+\b 438 | 439 | 440 | \b\-?(?:\d+(?:\.\d*)?|(?:\.\d+))\b 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | ` 449 | 450 | 451 | 452 | ` 453 | 454 | 455 | 456 | 457 | \\(?:'|"|n|r|t|b|f) 458 | 459 | 460 | 461 | 462 | 463 | " 464 | 465 | 466 | 467 | "|(?:(?<!\\)$) 468 | 469 | 470 | 471 | 472 | \\(?:\\|"|n|r|t|b|f) 473 | 474 | 475 | 476 | 477 | 478 | ' 479 | 480 | 481 | 482 | '|(?:(?<!\\)$) 483 | 484 | 485 | 486 | 487 | \\(?:\\|'|n|r|t|b|f) 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | (?i)(?<=[=(,:\+~!?\[|]|return|;|=>)\s*\/(?![\/*+{}?\r\n]) 496 | 497 | 498 | \/([cgimosuxy]+\b)? 499 | 500 | 501 | 502 | \\(?:\/) 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | (\b\s+([A-Za-zÀ-ÖØ-öø-ÿ0-9_\[\]]*)) 512 | 513 | bool 514 | byte 515 | complex64 516 | complex128 517 | float32 518 | float64 519 | int 520 | int8 521 | int16 522 | int32 523 | int64 524 | rune 525 | string 526 | uint 527 | uint8 528 | uint16 529 | uint32 530 | uint64 531 | uintptr 532 | 533 | 534 | 535 | 536 | \b\s+(\*?)(\[\d*\])?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_\.]*) 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | \b(import)\s*(\()? 550 | 551 | 552 | 553 | 554 | (\()? 555 | 556 | 557 | \s+([a-zA-ZÀ-ÖØ-öø-ÿ_]?[A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)[ \t]+"([a-zA-ZÀ-ÖØ-öø-ÿ_\.][A-Za-zÀ-ÖØ-öø-ÿ0-9-_\.\/]+)" 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | append 567 | cap 568 | close 569 | complex 570 | copy 571 | delete 572 | imag 573 | len 574 | make 575 | new 576 | panic 577 | print 578 | println 579 | real 580 | recover 581 | Alignof 582 | Offsetof 583 | Sizeof 584 | 585 | 586 | 587 | 588 | _ 589 | 590 | 591 | 592 | 593 | 594 | adler32 595 | aes 596 | ascii85 597 | asn1 598 | ast 599 | base64 600 | big 601 | bignum 602 | binary 603 | block 604 | bufio 605 | bytes 606 | crc32 607 | datafmt 608 | doc 609 | dwarf 610 | ebnf 611 | elf 612 | eval 613 | exec 614 | expvar 615 | flag 616 | flate 617 | fmt 618 | git85 619 | gob 620 | gosym 621 | gzip 622 | hash 623 | heap 624 | hex 625 | hmac 626 | http 627 | image 628 | io 629 | iotest 630 | iterable 631 | json 632 | list 633 | log 634 | macho 635 | malloc 636 | math 637 | md5 638 | net 639 | once 640 | os 641 | parser 642 | patch 643 | path 644 | pem 645 | png 646 | printer 647 | proc 648 | quick 649 | rand 650 | rc4 651 | reflect 652 | regexp 653 | ring 654 | rpc 655 | rsa 656 | runtime 657 | scanner 658 | script 659 | sha1 660 | sort 661 | stdio 662 | strconv 663 | strings 664 | subtle 665 | sync 666 | syscall 667 | tabwriter 668 | tar 669 | template 670 | testing 671 | time 672 | tls 673 | token 674 | unicode 675 | unsafe 676 | utf8 677 | vector 678 | x509 679 | xml 680 | zlib 681 | 682 | 683 | 684 | 685 | (\.)([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)(?=\()\b 686 | 687 | 688 | 689 | 690 | 691 | \b(?<!\.)([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)(?=\()\b 692 | 693 | 694 | 695 | \b[A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*\b 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | \{ 706 | 707 | 708 | 709 | 710 | 711 | \} 712 | 713 | 714 | [\(\[\)\]] 715 | 716 | 717 | (\+|\-|\*|\/|%|\+\+|\-\-|:\=|\=|\=\=|!\=|\+\=|\-\=|\*\=|\/\=|%\=|\<|\>|\<\=|\<\-|\>=|\=\=\=|!\=\=|&&|\||\|\||!|\^|&|\<\<|\>\>|~|\.\.\.) 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | \. 726 | 727 | 728 | \( 729 | 730 | 731 | \) 732 | 733 | 734 | (\()|(\)(?:;|(,))?) 735 | 736 | 737 | 738 | 739 | 740 | \? 741 | 742 | 743 | \; 744 | 745 | 746 | 747 | 748 | 749 | , 750 | 751 | 752 | 753 | (\{)|(\}(?:;|(,))?)|(\[)|(\](?:;|(,))?) 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | : 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | (([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*)\s*(:)) 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | ((?:(var)\s+)?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*)\s*(:?\=))(?!=) 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | ((?:(const)\s+)?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*)\s*(:?\=))(?!=) 789 | 790 | 791 | 792 | 793 | 794 | 795 | (([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$.]+)\s*(:?\=))(?!\=) 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | (\.)([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*)\s*(\() 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | \b[var|const]\b 817 | 818 | 819 | \( 820 | 821 | 822 | 823 | \) 824 | 825 | 826 | 827 | 828 | (?=\b(?:func|if|else|while|for)\b) 829 | 830 | 831 | 832 | , 833 | 834 | 835 | 836 | 837 | (?<!\=)\b([a-zØ-ö_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+(\*?)(\[\d*\])?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | (?<!\=)\b([A-ZÀ-ÖØ-ö_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\s+(\*?)(\[\d*\])?([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_]*)\b 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 857 | 858 | 860 | 861 | ([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*)\s*(\() 862 | 863 | 864 | 865 | 866 | 867 | ([A-Za-zÀ-ÖØ-öø-ÿ_][A-Za-zÀ-ÖØ-öø-ÿ0-9_][\w$]*) 868 | 869 | 870 | 871 | 872 | 873 | --------------------------------------------------------------------------------