| 🛟 Updated. 28d5985 k33g 16h ago | 1 | # snippets |
| 2 | |
| 3 | Reads the reusable pieces of text a project and a user keep in TOML, and groups them for a menu to show. |
| 4 | |
| 5 | Imports the standard library and the TOML parser, and nothing else — no tcell, no `ui`, no `app`. It is tested by writing files and reading them back. |
| 6 | |
| 7 | ## Two files, and why the project wins |
| 8 | |
| 9 | | File | Holds | |
| 10 | | --- | --- | |
| 11 | | `<project>/<p.ProjectDir()>/snippets.toml` | The project's | |
| 12 | | `$<p.SnippetDirEnvVar()>/snippets.toml`, else `<p.UserDir()>/snippets.toml` | The user's own | |
| 13 | |
| 14 | Both are read, the user's first. Your snippets should follow you between projects; a project's should arrive with a checkout — neither alone is the whole answer. |
| 15 | |
| 16 | Where a `group` **and** `name` clash, the project's replaces the user's. It is the more specific of the two statements, and the one a team agreed on. A same-name-different-group pair is two different snippets, not a clash. |
| 17 | |
| 18 | A missing file is not an error — most projects have none, and a user may have none either. A file that is **present but unreadable is** an error, so a typo is reported rather than silently dropping every snippet in it. |
| 19 | |
| 20 | ## Groups come out in file order |
| 21 | |
| 22 | `Groups(language)` gathers the snippets that apply into groups, and both the groups and the snippets inside them keep the order they were read. That is what makes the menu match the file: someone reordering the file sees the menu reorder. |
| 23 | |
| 24 | A snippet naming no `languages` applies everywhere — the common case is a licence header or a `TODO`, and making people list every language for that would be worse than showing a few too many. A group left with nothing after filtering does not appear at all. |
| 25 | |
| 26 | ## The starter file |
| 27 | |
| 28 | `Create` writes a commented file with worked examples and refuses to overwrite one that already exists. The bodies in the template contain the two characters `\` and `t`, not a tab: TOML interprets the escape when it reads the file, and a real tab would leave the template looking like whatever a reader's editor does with tabs. `TestTheCreatedFilesTabsSurviveTOML` is what holds that. |
| 29 | |
| 30 | It writes through a temporary file in the same directory, renamed into place — a rename is only atomic within one filesystem, and an interrupted write must leave the previous file intact. |
| 31 | |
| 32 | ## Public API |
| 33 | |
| 34 | | Name | What it does | |
| 35 | | --- | --- | |
| 36 | | `FileName` | `"snippets.toml"`. Both directories come from the `profile.Profile` every function here takes. | |
| 37 | | `Snippet{Name, Body, Group, Languages}` | One piece of text | |
| 38 | | `Group{Name, Snippets}` | One submenu's worth | |
| 39 | | `List` | Everything read, in order | |
| 40 | | `(List) Len() int` | How many there are in total | |
| 41 | | `(List) Groups(language string) []Group` | Those applying to a language, gathered into groups | |
| 42 | | `Load(projectDir) (List, error)` | Reads both files; a missing one is not an error | |
| 43 | | `Create(projectDir) (string, error)` | Writes the starter file; `ErrExists` rather than overwriting | |
| 44 | | `Exists(projectDir) bool` | Whether the project has a file to read | |
| 45 | | `ProjectPath(p, projectDir) string` | `<projectDir>/<p.ProjectDir()>/snippets.toml` | |
| 46 | | `UserDir(p) / UserPath(p) string` | Where the user's own live, or `""` | |
| 47 | | `ErrExists` | The one condition callers act on rather than report | |
| 48 | |
| 49 | ```go |
| 50 | list, err := snippets.Load(".") |
| 51 | if err != nil { |
| 52 | return err // a file is there but unreadable, which is worth saying |
| 53 | } |
| 54 | for _, group := range list.Groups("go") { |
| 55 | addSubmenu(group.Name, group.Snippets) |
| 56 | } |
| 57 | ``` |
| 58 | |
| 59 | ## Tests |
| 60 | |
| 61 | ```sh |
| 62 | make test |
| 63 | go test ./snippets/ |
| 64 | ``` |
| 65 | |
| 66 | Every test sets `TURBO_GO_SNIPPET_DIR` to an empty directory, so a run never reads the snippets of whoever is running it. |