detached 1a6c6c9

manifest.go RawHistoryFolder

1// Package spec holds the vendored Wayland protocol XML, the manifest that
2// describes it, the shared XML model, and the package naming rule.
3package spec
4
5import (
6	"embed"
7	"encoding/json"
8	"fmt"
9	"io/fs"
10	"sort"
11)
12
13// ModulePath is the import path prefix of the generated bindings.
14const ModulePath = "github.com/bnema/go-wayland-bindings"
15
16//go:embed manifest.json xml
17var files embed.FS
18
19// Manifest lists upstream sources and the protocols vendored from them.
20// It is written by cmd/wlbsync and never edited by hand.
21type Manifest struct {
22	Sources   []Source        `json:"sources"`
23	Protocols []ProtocolEntry `json:"protocols"`
24}
25
26// Source is a pinned upstream repository.
27type Source struct {
28	ID     string `json:"id"`
29	URL    string `json:"url"`
30	Ref    string `json:"ref"`    // tag or branch name
31	Commit string `json:"commit"` // resolved commit SHA
32}
33
34// ProtocolEntry describes one vendored protocol.
35type ProtocolEntry struct {
36	Package    string           `json:"package"`
37	XML        string           `json:"xml"`    // file name under spec/xml
38	Source     string           `json:"source"` // Source.ID
39	Path       string           `json:"path"`   // path inside the upstream repository
40	SHA256     string           `json:"sha256"`
41	License    string           `json:"license"` // SPDX identifier
42	Interfaces []InterfaceEntry `json:"interfaces"`
43	Deps       []string         `json:"deps"` // packages owning referenced interfaces
44}
45
46// InterfaceEntry records an interface and its highest version.
47type InterfaceEntry struct {
48	Name    string `json:"name"`
49	Version int    `json:"version"`
50}
51
52// Load returns the embedded manifest.
53func Load() (*Manifest, error) {
54	return LoadFS(files)
55}
56
57// LoadFS reads manifest.json from fsys.
58func LoadFS(fsys fs.FS) (*Manifest, error) {
59	b, err := fs.ReadFile(fsys, "manifest.json")
60	if err != nil {
61		return nil, fmt.Errorf("read manifest: %w", err)
62	}
63	var m Manifest
64	if err := json.Unmarshal(b, &m); err != nil {
65		return nil, fmt.Errorf("decode manifest: %w", err)
66	}
67	return &m, nil
68}
69
70// Open returns the embedded XML of package pkg.
71func Open(pkg string) ([]byte, error) {
72	m, err := Load()
73	if err != nil {
74		return nil, err
75	}
76	return m.Open(pkg)
77}
78
79// Open returns the embedded XML of package pkg, which must be listed in m.
80func (m *Manifest) Open(pkg string) ([]byte, error) {
81	e, ok := m.Package(pkg)
82	if !ok {
83		return nil, fmt.Errorf("unknown protocol package %q", pkg)
84	}
85	return fs.ReadFile(files, "xml/"+e.XML)
86}
87
88// Package returns the entry named pkg.
89func (m *Manifest) Package(pkg string) (ProtocolEntry, bool) {
90	for _, e := range m.Protocols {
91		if e.Package == pkg {
92			return e, true
93		}
94	}
95	return ProtocolEntry{}, false
96}
97
98// Owners maps every interface name to the package that defines it.
99func (m *Manifest) Owners() map[string]string {
100	out := make(map[string]string)
101	for _, e := range m.Protocols {
102		for _, it := range e.Interfaces {
103			out[it.Name] = e.Package
104		}
105	}
106	return out
107}
108
109// Lookup returns the package defining interface iface.
110func (m *Manifest) Lookup(iface string) (string, bool) {
111	p, ok := m.Owners()[iface]
112	return p, ok
113}
114
115// Sort orders sources by ID and protocols by package, for stable output.
116func (m *Manifest) Sort() {
117	sort.Slice(m.Sources, func(i, j int) bool { return m.Sources[i].ID < m.Sources[j].ID })
118	sort.Slice(m.Protocols, func(i, j int) bool { return m.Protocols[i].Package < m.Protocols[j].Package })
119}
120
121// Marshal encodes m as indented JSON with a trailing newline.
122func (m *Manifest) Marshal() ([]byte, error) {
123	b, err := json.MarshalIndent(m, "", "  ")
124	if err != nil {
125		return nil, err
126	}
127	return append(b, '\n'), nil
128}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 1

↑↓ moveenter openesc close