detached a2af3ad

p3-config: remove user-facing [transcoding] config schema/defaults

- Remove TranscodingConfig field from Config struct (no longer user-facing)
- Remove transcoding default constants and DefaultConfig() entry
- Remove setTranscodingDefaults from loader (no viper defaults registered)
- Remove transcoding assertions from defaults_test, loader_test, writer_test
- Remove TestLoad_AppliesTranscodingDefaultsWhenSectionMissing
- Keep TranscodingConfig type (deprecated) for build compat with transcoder pkg
- Existing config files with [transcoding] section: unknown keys will be silently
  ignored by mapstructure (viper unmarshals only known struct fields)
commit
a2af3ada71a26dc18527356f91dedd79da9af1ce
author
brice · · 2026-04-28 03:59 UTC
parent
e49694e
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
6 files · +11 -99
M internal/infrastructure/config/defaults.go +0 -12
@@ -71,12 +71,6 @@ const (
7171 defaultWebViewPoolPrewarmCount = 4 // WebViews to pre-create at startup
7272 defaultCEFWindowlessFrameRate = 60 // OSR frame rate for CEF
7373
74- // Transcoding defaults
75- defaultTranscodingEnabled = false
76- defaultTranscodingHWAccel = "auto"
77- defaultTranscodingMaxConcurrent = 3
78- defaultTranscodingQuality = "medium"
79-
8074 // Skia threading defaults (0 = unset, -1 = unset for GPU threads)
8175 defaultSkiaCPUPaintingThreads = 0
8276 defaultSkiaGPUPaintingThreads = -1 // -1 means unset; 0 would disable GPU tile painting
@@ -324,12 +318,6 @@ func DefaultConfig() *Config {
324318 Downloads: DownloadsConfig{
325319 Path: "", // Empty = use XDG_DOWNLOAD_DIR or ~/Downloads
326320 },
327- Transcoding: TranscodingConfig{
328- Enabled: defaultTranscodingEnabled,
329- HWAccel: defaultTranscodingHWAccel,
330- MaxConcurrent: defaultTranscodingMaxConcurrent,
331- Quality: defaultTranscodingQuality,
332- },
333321 }
334322 }
335323
@@ -71,12 +71,6 @@ const (
71 defaultWebViewPoolPrewarmCount = 4 // WebViews to pre-create at startup71 defaultWebViewPoolPrewarmCount = 4 // WebViews to pre-create at startup
72 defaultCEFWindowlessFrameRate = 60 // OSR frame rate for CEF72 defaultCEFWindowlessFrameRate = 60 // OSR frame rate for CEF
73 73
74- // Transcoding defaults
75- defaultTranscodingEnabled = false
76- defaultTranscodingHWAccel = "auto"
77- defaultTranscodingMaxConcurrent = 3
78- defaultTranscodingQuality = "medium"
79-
80 // Skia threading defaults (0 = unset, -1 = unset for GPU threads)74 // Skia threading defaults (0 = unset, -1 = unset for GPU threads)
81 defaultSkiaCPUPaintingThreads = 075 defaultSkiaCPUPaintingThreads = 0
82 defaultSkiaGPUPaintingThreads = -1 // -1 means unset; 0 would disable GPU tile painting76 defaultSkiaGPUPaintingThreads = -1 // -1 means unset; 0 would disable GPU tile painting
@@ -324,12 +318,6 @@ func DefaultConfig() *Config {
324 Downloads: DownloadsConfig{318 Downloads: DownloadsConfig{
325 Path: "", // Empty = use XDG_DOWNLOAD_DIR or ~/Downloads319 Path: "", // Empty = use XDG_DOWNLOAD_DIR or ~/Downloads
326 },320 },
327- Transcoding: TranscodingConfig{
328- Enabled: defaultTranscodingEnabled,
329- HWAccel: defaultTranscodingHWAccel,
330- MaxConcurrent: defaultTranscodingMaxConcurrent,
331- Quality: defaultTranscodingQuality,
332- },
333 }321 }
334 }322 }
335 323
M internal/infrastructure/config/defaults_test.go +0 -4
@@ -13,10 +13,6 @@ func TestDefaultConfig_CoreDefaults(t *testing.T) {
1313 assert.Equal(t, defaultMaxLogFiles, cfg.Logging.MaxFiles)
1414 assert.False(t, cfg.Logging.CaptureGTKLogs)
1515 assert.False(t, cfg.Media.ShowDiagnosticsOnStartup)
16- assert.False(t, cfg.Transcoding.Enabled)
17- assert.Equal(t, "auto", cfg.Transcoding.HWAccel)
18- assert.Equal(t, 3, cfg.Transcoding.MaxConcurrent)
19- assert.Equal(t, "medium", cfg.Transcoding.Quality)
2016
2117 // Engine defaults (replaces old Performance/Privacy sections)
2218 assert.Equal(t, "webkit", cfg.Engine.Type)
@@ -13,10 +13,6 @@ func TestDefaultConfig_CoreDefaults(t *testing.T) {
13 assert.Equal(t, defaultMaxLogFiles, cfg.Logging.MaxFiles)13 assert.Equal(t, defaultMaxLogFiles, cfg.Logging.MaxFiles)
14 assert.False(t, cfg.Logging.CaptureGTKLogs)14 assert.False(t, cfg.Logging.CaptureGTKLogs)
15 assert.False(t, cfg.Media.ShowDiagnosticsOnStartup)15 assert.False(t, cfg.Media.ShowDiagnosticsOnStartup)
16- assert.False(t, cfg.Transcoding.Enabled)
17- assert.Equal(t, "auto", cfg.Transcoding.HWAccel)
18- assert.Equal(t, 3, cfg.Transcoding.MaxConcurrent)
19- assert.Equal(t, "medium", cfg.Transcoding.Quality)
20 16
21 // Engine defaults (replaces old Performance/Privacy sections)17 // Engine defaults (replaces old Performance/Privacy sections)
22 assert.Equal(t, "webkit", cfg.Engine.Type)18 assert.Equal(t, "webkit", cfg.Engine.Type)
M internal/infrastructure/config/loader.go +1 -8
@@ -417,7 +417,6 @@ func (m *Manager) setDefaults() {
417417 m.setDebugDefaults(defaults)
418418 m.setAppearanceDefaults(defaults)
419419 m.setEngineDefaults(defaults)
420- m.setTranscodingDefaults(defaults)
421420 m.setZoomAndScaleDefaults(defaults)
422421 m.setWorkspaceDefaults(defaults)
423422 m.setContentFilteringDefaults(defaults)
@@ -611,13 +610,7 @@ func (m *Manager) setEngineDefaults(defaults *Config) {
611610 m.viper.SetDefault("engine.webkit.network_process_memory_strict_threshold", wk.NetworkProcessMemoryStrictThreshold)
612611 }
613612
614-func (m *Manager) setTranscodingDefaults(defaults *Config) {
615- tc := defaults.Transcoding
616- m.viper.SetDefault("transcoding.enabled", tc.Enabled)
617- m.viper.SetDefault("transcoding.hwaccel", tc.HWAccel)
618- m.viper.SetDefault("transcoding.max_concurrent", tc.MaxConcurrent)
619- m.viper.SetDefault("transcoding.quality", tc.Quality)
620-}
613+
621614
622615 // New returns a new default configuration instance.
623616 // This is a convenience function for getting default config without the full manager.
@@ -417,7 +417,6 @@ func (m *Manager) setDefaults() {
417 m.setDebugDefaults(defaults)417 m.setDebugDefaults(defaults)
418 m.setAppearanceDefaults(defaults)418 m.setAppearanceDefaults(defaults)
419 m.setEngineDefaults(defaults)419 m.setEngineDefaults(defaults)
420- m.setTranscodingDefaults(defaults)
421 m.setZoomAndScaleDefaults(defaults)420 m.setZoomAndScaleDefaults(defaults)
422 m.setWorkspaceDefaults(defaults)421 m.setWorkspaceDefaults(defaults)
423 m.setContentFilteringDefaults(defaults)422 m.setContentFilteringDefaults(defaults)
@@ -611,13 +610,7 @@ func (m *Manager) setEngineDefaults(defaults *Config) {
611 m.viper.SetDefault("engine.webkit.network_process_memory_strict_threshold", wk.NetworkProcessMemoryStrictThreshold)610 m.viper.SetDefault("engine.webkit.network_process_memory_strict_threshold", wk.NetworkProcessMemoryStrictThreshold)
612 }611 }
613 612
614-func (m *Manager) setTranscodingDefaults(defaults *Config) {613+
615- tc := defaults.Transcoding
616- m.viper.SetDefault("transcoding.enabled", tc.Enabled)
617- m.viper.SetDefault("transcoding.hwaccel", tc.HWAccel)
618- m.viper.SetDefault("transcoding.max_concurrent", tc.MaxConcurrent)
619- m.viper.SetDefault("transcoding.quality", tc.Quality)
620-}
621 614
622 // New returns a new default configuration instance.615 // New returns a new default configuration instance.
623 // This is a convenience function for getting default config without the full manager.616 // This is a convenience function for getting default config without the full manager.
M internal/infrastructure/config/loader_test.go +0 -38
@@ -1,13 +1,10 @@
11 package config
22
33 import (
4- "os"
5- "path/filepath"
64 "testing"
75
86 "github.com/spf13/viper"
97 "github.com/stretchr/testify/assert"
10- "github.com/stretchr/testify/require"
118 )
129
1310 func TestSetEngineDefaults(t *testing.T) {
@@ -27,12 +24,6 @@ func TestSetEngineDefaults(t *testing.T) {
2724 assert.Equal(t, "auto", mgr.viper.GetString("engine.webkit.gl_rendering_mode"))
2825 assert.False(t, mgr.viper.GetBool("engine.webkit.disable_dmabuf_renderer"))
2926
30- // Transcoding defaults
31- assert.False(t, mgr.viper.GetBool("transcoding.enabled"))
32- assert.Equal(t, "auto", mgr.viper.GetString("transcoding.hwaccel"))
33- assert.Equal(t, 3, mgr.viper.GetInt("transcoding.max_concurrent"))
34- assert.Equal(t, "medium", mgr.viper.GetString("transcoding.quality"))
35-
3627 // Old sections should NOT be registered as defaults
3728 assert.Empty(t, mgr.viper.GetString("privacy.cookie_policy"))
3829 assert.Empty(t, mgr.viper.GetString("rendering.mode"))
@@ -49,33 +40,4 @@ func TestNormalizeConfig_EngineCookiePolicy(t *testing.T) {
4940 assert.Equal(t, CookiePolicyAlways, cfg.Engine.CookiePolicy)
5041 }
5142
52-func TestLoad_AppliesTranscodingDefaultsWhenSectionMissing(t *testing.T) {
53- t.Setenv("XDG_CONFIG_HOME", t.TempDir())
54- t.Setenv("XDG_DATA_HOME", t.TempDir())
55- t.Setenv("XDG_STATE_HOME", t.TempDir())
56- t.Setenv("XDG_CACHE_HOME", t.TempDir())
57-
58- configDir, err := GetConfigDir()
59- require.NoError(t, err)
60-
61- err = os.MkdirAll(configDir, dirPerm)
62- require.NoError(t, err)
6343
64- configPath := filepath.Join(configDir, "config.toml")
65- err = os.WriteFile(configPath, []byte(`
66-[engine]
67-type = "cef"
68-`), filePerm)
69- require.NoError(t, err)
70-
71- mgr, err := NewManager()
72- require.NoError(t, err)
73- require.NoError(t, mgr.Load())
74-
75- cfg := mgr.Get()
76- require.NotNil(t, cfg)
77- assert.False(t, cfg.Transcoding.Enabled)
78- assert.Equal(t, "auto", cfg.Transcoding.HWAccel)
79- assert.Equal(t, 3, cfg.Transcoding.MaxConcurrent)
80- assert.Equal(t, "medium", cfg.Transcoding.Quality)
81-}
@@ -1,13 +1,10 @@
1 package config1 package config
2 2
3 import (3 import (
4- "os"
5- "path/filepath"
6 "testing"4 "testing"
7 5
8 "github.com/spf13/viper"6 "github.com/spf13/viper"
9 "github.com/stretchr/testify/assert"7 "github.com/stretchr/testify/assert"
10- "github.com/stretchr/testify/require"
11 )8 )
12 9
13 func TestSetEngineDefaults(t *testing.T) {10 func TestSetEngineDefaults(t *testing.T) {
@@ -27,12 +24,6 @@ func TestSetEngineDefaults(t *testing.T) {
27 assert.Equal(t, "auto", mgr.viper.GetString("engine.webkit.gl_rendering_mode"))24 assert.Equal(t, "auto", mgr.viper.GetString("engine.webkit.gl_rendering_mode"))
28 assert.False(t, mgr.viper.GetBool("engine.webkit.disable_dmabuf_renderer"))25 assert.False(t, mgr.viper.GetBool("engine.webkit.disable_dmabuf_renderer"))
29 26
30- // Transcoding defaults
31- assert.False(t, mgr.viper.GetBool("transcoding.enabled"))
32- assert.Equal(t, "auto", mgr.viper.GetString("transcoding.hwaccel"))
33- assert.Equal(t, 3, mgr.viper.GetInt("transcoding.max_concurrent"))
34- assert.Equal(t, "medium", mgr.viper.GetString("transcoding.quality"))
35-
36 // Old sections should NOT be registered as defaults27 // Old sections should NOT be registered as defaults
37 assert.Empty(t, mgr.viper.GetString("privacy.cookie_policy"))28 assert.Empty(t, mgr.viper.GetString("privacy.cookie_policy"))
38 assert.Empty(t, mgr.viper.GetString("rendering.mode"))29 assert.Empty(t, mgr.viper.GetString("rendering.mode"))
@@ -49,33 +40,4 @@ func TestNormalizeConfig_EngineCookiePolicy(t *testing.T) {
49 assert.Equal(t, CookiePolicyAlways, cfg.Engine.CookiePolicy)40 assert.Equal(t, CookiePolicyAlways, cfg.Engine.CookiePolicy)
50 }41 }
51 42
52-func TestLoad_AppliesTranscodingDefaultsWhenSectionMissing(t *testing.T) {
53- t.Setenv("XDG_CONFIG_HOME", t.TempDir())
54- t.Setenv("XDG_DATA_HOME", t.TempDir())
55- t.Setenv("XDG_STATE_HOME", t.TempDir())
56- t.Setenv("XDG_CACHE_HOME", t.TempDir())
57-
58- configDir, err := GetConfigDir()
59- require.NoError(t, err)
60-
61- err = os.MkdirAll(configDir, dirPerm)
62- require.NoError(t, err)
63 43
64- configPath := filepath.Join(configDir, "config.toml")
65- err = os.WriteFile(configPath, []byte(`
66-[engine]
67-type = "cef"
68-`), filePerm)
69- require.NoError(t, err)
70-
71- mgr, err := NewManager()
72- require.NoError(t, err)
73- require.NoError(t, mgr.Load())
74-
75- cfg := mgr.Get()
76- require.NotNil(t, cfg)
77- assert.False(t, cfg.Transcoding.Enabled)
78- assert.Equal(t, "auto", cfg.Transcoding.HWAccel)
79- assert.Equal(t, 3, cfg.Transcoding.MaxConcurrent)
80- assert.Equal(t, "medium", cfg.Transcoding.Quality)
81-}
M internal/infrastructure/config/schema.go +10 -15
@@ -110,8 +110,6 @@ type Config struct {
110110 Downloads DownloadsConfig `mapstructure:"downloads" yaml:"downloads" toml:"downloads"`
111111 // Engine holds engine selection and unified engine options.
112112 Engine EngineConfig `mapstructure:"engine" toml:"engine" yaml:"engine"`
113- // Transcoding controls GPU-accelerated media transcoding for proprietary codecs.
114- Transcoding TranscodingConfig `mapstructure:"transcoding" yaml:"transcoding" toml:"transcoding"`
115113 }
116114
117115 // CookiePolicy controls cookie acceptance behavior.
@@ -384,19 +382,16 @@ type DownloadsConfig struct {
384382 Path string `mapstructure:"path" yaml:"path" toml:"path"`
385383 }
386384
385+// Deprecated: TranscodingConfig is retained only for build compatibility with
386+// the internal/infrastructure/transcoder package (to be deleted in p3-delete).
387+// No public config schema or defaults are registered for it.
388+//
387389 // TranscodingConfig controls GPU-accelerated media transcoding.
388-// When enabled, proprietary video formats (H.264, HEVC) are transcoded
389-// to open codecs (VP9, AV1) that CEF can decode natively.
390390 type TranscodingConfig struct {
391- // Enabled controls whether transcoding is active (default: false).
392- Enabled bool `mapstructure:"enabled" yaml:"enabled" toml:"enabled"`
393- // HWAccel selects the hardware acceleration API: "auto", "vaapi", or "nvenc".
394- // Default: "auto" (tries VAAPI first, then CUDA).
395- HWAccel string `mapstructure:"hwaccel" yaml:"hwaccel" toml:"hwaccel"`
396- // MaxConcurrent is the maximum number of simultaneous transcode sessions.
397- // Default: 3.
398- MaxConcurrent int `mapstructure:"max_concurrent" yaml:"max_concurrent" toml:"max_concurrent"`
399- // Quality controls the encode quality preset: "low", "medium", or "high".
400- // Default: "medium".
401- Quality string `mapstructure:"quality" yaml:"quality" toml:"quality"`
391+ Enabled bool `mapstructure:"enabled" yaml:"enabled" toml:"enabled"`
392+ HWAccel string `mapstructure:"hwaccel" yaml:"hwaccel" toml:"hwaccel"`
393+ MaxConcurrent int `mapstructure:"max_concurrent" yaml:"max_concurrent" toml:"max_concurrent"`
394+ Quality string `mapstructure:"quality" yaml:"quality" toml:"quality"`
402395 }
396+
397+
@@ -110,8 +110,6 @@ type Config struct {
110 Downloads DownloadsConfig `mapstructure:"downloads" yaml:"downloads" toml:"downloads"`110 Downloads DownloadsConfig `mapstructure:"downloads" yaml:"downloads" toml:"downloads"`
111 // Engine holds engine selection and unified engine options.111 // Engine holds engine selection and unified engine options.
112 Engine EngineConfig `mapstructure:"engine" toml:"engine" yaml:"engine"`112 Engine EngineConfig `mapstructure:"engine" toml:"engine" yaml:"engine"`
113- // Transcoding controls GPU-accelerated media transcoding for proprietary codecs.
114- Transcoding TranscodingConfig `mapstructure:"transcoding" yaml:"transcoding" toml:"transcoding"`
115 }113 }
116 114
117 // CookiePolicy controls cookie acceptance behavior.115 // CookiePolicy controls cookie acceptance behavior.
@@ -384,19 +382,16 @@ type DownloadsConfig struct {
384 Path string `mapstructure:"path" yaml:"path" toml:"path"`382 Path string `mapstructure:"path" yaml:"path" toml:"path"`
385 }383 }
386 384
385+// Deprecated: TranscodingConfig is retained only for build compatibility with
386+// the internal/infrastructure/transcoder package (to be deleted in p3-delete).
387+// No public config schema or defaults are registered for it.
388+//
387 // TranscodingConfig controls GPU-accelerated media transcoding.389 // TranscodingConfig controls GPU-accelerated media transcoding.
388-// When enabled, proprietary video formats (H.264, HEVC) are transcoded
389-// to open codecs (VP9, AV1) that CEF can decode natively.
390 type TranscodingConfig struct {390 type TranscodingConfig struct {
391- // Enabled controls whether transcoding is active (default: false).391+ Enabled bool `mapstructure:"enabled" yaml:"enabled" toml:"enabled"`
392- Enabled bool `mapstructure:"enabled" yaml:"enabled" toml:"enabled"`392+ HWAccel string `mapstructure:"hwaccel" yaml:"hwaccel" toml:"hwaccel"`
393- // HWAccel selects the hardware acceleration API: "auto", "vaapi", or "nvenc".393+ MaxConcurrent int `mapstructure:"max_concurrent" yaml:"max_concurrent" toml:"max_concurrent"`
394- // Default: "auto" (tries VAAPI first, then CUDA).394+ Quality string `mapstructure:"quality" yaml:"quality" toml:"quality"`
395- HWAccel string `mapstructure:"hwaccel" yaml:"hwaccel" toml:"hwaccel"`
396- // MaxConcurrent is the maximum number of simultaneous transcode sessions.
397- // Default: 3.
398- MaxConcurrent int `mapstructure:"max_concurrent" yaml:"max_concurrent" toml:"max_concurrent"`
399- // Quality controls the encode quality preset: "low", "medium", or "high".
400- // Default: "medium".
401- Quality string `mapstructure:"quality" yaml:"quality" toml:"quality"`
402 }395 }
396+
397+
M internal/infrastructure/config/writer_test.go +0 -22
@@ -1,7 +1,6 @@
11 package config
22
33 import (
4- "bytes"
54 "os"
65 "path/filepath"
76 "strings"
@@ -44,27 +43,6 @@ func TestWriteConfigOrdered(t *testing.T) {
4443 }
4544 }
4645
47- if !strings.Contains(string(content), "[transcoding]") {
48- t.Fatalf("expected transcoding section in generated config, got:\n%s", string(content))
49- }
50- // Match "enabled = false" specifically within the [transcoding] section to
51- // avoid false positives from other sections that may also have an enabled key.
52- transcodingIdx := bytes.Index(content, []byte("[transcoding]"))
53- if transcodingIdx < 0 {
54- t.Fatalf("expected transcoding section in generated config, got:\n%s", string(content))
55- }
56- afterTranscoding := content[transcodingIdx:]
57- nextSection := bytes.Index(afterTranscoding[1:], []byte("\n["))
58- var transcodingBlock []byte
59- if nextSection >= 0 {
60- transcodingBlock = afterTranscoding[:nextSection+1]
61- } else {
62- transcodingBlock = afterTranscoding
63- }
64- if !bytes.Contains(transcodingBlock, []byte("enabled = false")) {
65- t.Fatalf("expected enabled = false in [transcoding] section, got:\n%s", string(transcodingBlock))
66- }
67-
6846 t.Logf("Found %d sections, all sorted", len(sections))
6947
7048 // Print first 50 lines for debugging
@@ -1,7 +1,6 @@
1 package config1 package config
2 2
3 import (3 import (
4- "bytes"
5 "os"4 "os"
6 "path/filepath"5 "path/filepath"
7 "strings"6 "strings"
@@ -44,27 +43,6 @@ func TestWriteConfigOrdered(t *testing.T) {
44 }43 }
45 }44 }
46 45
47- if !strings.Contains(string(content), "[transcoding]") {
48- t.Fatalf("expected transcoding section in generated config, got:\n%s", string(content))
49- }
50- // Match "enabled = false" specifically within the [transcoding] section to
51- // avoid false positives from other sections that may also have an enabled key.
52- transcodingIdx := bytes.Index(content, []byte("[transcoding]"))
53- if transcodingIdx < 0 {
54- t.Fatalf("expected transcoding section in generated config, got:\n%s", string(content))
55- }
56- afterTranscoding := content[transcodingIdx:]
57- nextSection := bytes.Index(afterTranscoding[1:], []byte("\n["))
58- var transcodingBlock []byte
59- if nextSection >= 0 {
60- transcodingBlock = afterTranscoding[:nextSection+1]
61- } else {
62- transcodingBlock = afterTranscoding
63- }
64- if !bytes.Contains(transcodingBlock, []byte("enabled = false")) {
65- t.Fatalf("expected enabled = false in [transcoding] section, got:\n%s", string(transcodingBlock))
66- }
67-
68 t.Logf("Found %d sections, all sorted", len(sections))46 t.Logf("Found %d sections, all sorted", len(sections))
69 47
70 // Print first 50 lines for debugging48 // Print first 50 lines for debugging

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 8

Tags 42

↑↓ moveenter openesc close