v0.1.0 2c367cd

main.go RawHistoryFolder

1// Command trayitems lists the StatusNotifierItems registered on the session
2// bus, then prints their changes as they happen.
3package main
4
5import (
6	"fmt"
7	"log"
8	"strings"
9
10	"github.com/bnema/zerobus"
11)
12
13const (
14	watcher     = "org.kde.StatusNotifierWatcher"
15	watcherPath = "/StatusNotifierWatcher"
16	props       = "org.freedesktop.DBus.Properties"
17	item        = "org.kde.StatusNotifierItem"
18)
19
20func main() {
21	c, err := zerobus.SessionBus()
22	if err != nil {
23		log.Fatal(err)
24	}
25	defer func() { _ = c.Close() }()
26
27	e := c.NewCall(watcher, watcherPath, props, "Get", "ss")
28	e.Str(watcher)
29	e.Str("RegisteredStatusNotifierItems")
30	m, err := c.Call()
31	if err != nil {
32		log.Fatal(err)
33	}
34	// The reply is a variant holding an array of strings. Copy the names:
35	// the next call reuses the buffer they point into.
36	r := m.Body()
37	var items []string
38	if r.Variant() == "as" {
39		end := r.Array('s')
40		for r.More(end) {
41			items = append(items, strings.Clone(r.Str()))
42		}
43	}
44	if r.Err() != nil {
45		log.Fatal(r.Err())
46	}
47
48	for _, it := range items {
49		// An item is "bus-name/object/path", or only a bus name.
50		dest, path, ok := strings.Cut(it, "/")
51		if ok {
52			path = "/" + path
53		} else {
54			path = "/StatusNotifierItem"
55		}
56		fmt.Printf("%s\n  id=%q icon=%q status=%q\n", it, get(c, dest, path, "Id"), get(c, dest, path, "IconName"), get(c, dest, path, "Status"))
57	}
58
59	if err := c.AddMatch("type='signal',interface='" + item + "'"); err != nil {
60		log.Fatal(err)
61	}
62	fmt.Println("waiting for changes (Ctrl+C to stop)")
63	for {
64		m, err := c.ReadMessage()
65		if err != nil {
66			log.Fatal(err)
67		}
68		if m.Type == zerobus.TypeSignal {
69			fmt.Printf("%s %s %s\n", m.Sender, m.Path, m.Member)
70		}
71	}
72}
73
74// get reads a string property, or returns "" when it has none.
75func get(c *zerobus.Conn, dest, path, name string) string {
76	e := c.NewCall(dest, path, props, "Get", "ss")
77	e.Str(item)
78	e.Str(name)
79	m, err := c.Call()
80	if err != nil {
81		return ""
82	}
83	r := m.Body()
84	if r.Variant() != "s" {
85		return ""
86	}
87	return strings.Clone(r.Str())
88}

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 3

↑↓ moveenter openesc close