1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
|
# Global git config in the drawer
## Goal
Review and edit the user's global git configuration from the drawer: every
key, not only the three the user page derives. Per-repository, system and
`[include]`d configs are out of scope.
## Measured
- The global config is `~/.gitconfig`: 59 keys over 20 sections, one of
them (`versionsort.prereleasesuffix`) set six times. `~/.config/git/`
holds no `config`, so there is one global file.
- git 2.55: `--fixed-value` (2.30+) makes a value argument a literal rather
than a regex, so a write can target one value of a multi-valued key.
- `git config --global -z --list` separates entries with NUL and key from
value with the first newline, so values holding `=` or newlines survive.
- The editor is `/usr/bin/sublime_text`; there is no `subl` on PATH.
## Approach
All reads and writes go through `git config`. git keeps the file's comments,
layout and quoting; the shell never parses or writes `~/.gitconfig` itself.
Rewriting the file from QML was rejected: it loses comments and has to
reimplement git's quoting.
## Module: `desktop/modules/git/`
- `GitModule.qml`: name `git`, label `Git config`, `tiled: false`, a page,
and `up: "user"` (see Drawer below).
- `gitcfg`: bash helper, the only thing that touches git. Every write puts
`--` before the key, so a key or value starting with `-` is an argument,
not an option (checked against git 2.55 with `--add`, `--replace-all` and
`--unset`).
- `list`: `git config --global -z --list`, printed as is.
- `set <key> <old> <new>`: `git config --global --fixed-value
--replace-all <key> <new> <old>`. Only the value equal to `<old>`
changes, even on a multi-valued key.
- `add <key> <value>`: `git config --global --add <key> <value>`.
- `unset <key> <value>`: `git config --global --fixed-value --unset <key>
<value>`. Removes only that value.
- git's stderr passes through and its exit status is the helper's.
- `Git.js` (`.pragma library`): `parse(text)` turns the `-z` output into
`[{section, key, value}]` in file order, `section` being everything before
the last dot (`color.branch.remote` is section `color.branch`). Tested by
`test_git.js` under node, as `User.js` is.
- `GitPage.qml`:
- Top: an "Edit in editor" button running `sublime_text ~/.gitconfig`,
detached, so the drawer can close while it stays open.
- The keys grouped under their section, one row per value: the key name,
then the value as an inline text field. Enter saves through `set`,
Escape restores the old value; Escape on an unfocused page still steps
back as on every page.
- A remove button per row, through `unset`. No confirmation: a removed
value is re-added from the Add row.
- An Add row at the bottom: `section.key` and value, through `add`.
- After every write, and when the page opens, the list is read again from
git. A failed write shows git's stderr under the row it came from and
the list is reloaded, so the field shows what git really holds.
## User page link
The user page's Git section gains a "More git settings" button that opens
the git page.
## Drawer
- `Page.qml` gains a `go(name)` signal; the drawer connects it to
`show(name)`, so a page can open another module's page.
- `Module.qml` gains `property string up: ""`: the page `back()` returns to.
Empty means the grid, today's behaviour. `back()` sets `page` to
`current.up`, and the page's back arrow calls `back()` rather than
clearing `page` itself, so the arrow, Escape and the mouse back button
agree.
## Checks
- `test-gitcfg.sh` runs `gitcfg` against a throwaway `GIT_CONFIG_GLOBAL` in
a temp directory: `list` of a multi-valued key, `set` of one value of
three, `unset` of one value of three, `add`, a value containing `=`, and a
value starting with `-`.
- `node desktop/modules/git/test_git.js` for `parse`.
- The page is checked by the user, by hand.
|