diff --git a/README.md b/README.md index f29b4f7e4..07eb99b9b 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ Gdu can read (and write) YAML configuration file. * To configure gdu to permanently run in gray-scale color mode: ``` -echo "no-color: true" > ~/.gdu.yaml +echo "no-color: true" >> ~/.gdu.yaml ``` * To set default sorting in configuration file: @@ -170,6 +170,12 @@ sorting: order: desc ``` +* To configure gdu to set CWD variable when browsing directories: + +``` +echo "change-cwd: true" >> ~/.gdu.yaml +``` + * To save the current configuration ``` diff --git a/cmd/gdu/app/app.go b/cmd/gdu/app/app.go index 63afcd884..445d66776 100644 --- a/cmd/gdu/app/app.go +++ b/cmd/gdu/app/app.go @@ -65,6 +65,7 @@ type Flags struct { UseSIPrefix bool `yaml:"use-si-prefix"` NoPrefix bool `yaml:"no-prefix"` WriteConfig bool `yaml:"-"` + ChangeCwd bool `yaml:"change-cwd"` Style Style `yaml:"style"` Sorting Sorting `yaml:"sorting"` } @@ -240,6 +241,11 @@ func (a *App) createUI() (UI, error) { ui.SetDefaultSorting(a.Flags.Sorting.By, a.Flags.Sorting.Order) }) } + if a.Flags.ChangeCwd != false { + opts = append(opts, func(ui *tui.UI) { + ui.SetChangeCwdFn(os.Chdir) + }) + } ui = tui.CreateUI( a.TermApp, diff --git a/cmd/gdu/app/app_test.go b/cmd/gdu/app/app_test.go index 947f45337..2aa5cf1dd 100644 --- a/cmd/gdu/app/app_test.go +++ b/cmd/gdu/app/app_test.go @@ -214,6 +214,24 @@ func TestAnalyzePathWithExport(t *testing.T) { assert.Nil(t, err) } +func TestAnalyzePathWithChdir(t *testing.T) { + fin := testdir.CreateTestDir() + defer fin() + + out, err := runApp( + &Flags{ + LogFile: "/dev/null", + ChangeCwd: true, + }, + []string{"test_dir"}, + true, + testdev.DevicesInfoGetterMock{}, + ) + + assert.Empty(t, out) + assert.Nil(t, err) +} + func TestReadAnalysisFromFile(t *testing.T) { out, err := runApp( &Flags{LogFile: "/dev/null", InputFile: "../../../internal/testdata/test.json"}, diff --git a/tui/actions_test.go b/tui/actions_test.go index 325c71f59..86e82fca7 100644 --- a/tui/actions_test.go +++ b/tui/actions_test.go @@ -2,6 +2,7 @@ package tui import ( "bytes" + "errors" "os" "testing" @@ -271,6 +272,76 @@ func TestViewFile(t *testing.T) { assert.Equal(t, 'j', event.Rune()) } +func TestChangeCwd(t *testing.T) { + fin := testdir.CreateTestDir() + defer fin() + simScreen := testapp.CreateSimScreen(50, 50) + defer simScreen.Fini() + cwd := "" + + opt := func(ui *UI) { + ui.SetChangeCwdFn(func(p string) error { + cwd = p + return nil + }) + } + app := testapp.CreateMockedApp(true) + ui := CreateUI(app, simScreen, &bytes.Buffer{}, false, true, false, false, false, opt) + ui.done = make(chan struct{}) + err := ui.AnalyzePath("test_dir", nil) + assert.Nil(t, err) + + <-ui.done // wait for analyzer + + for _, f := range ui.app.(*testapp.MockedApp).GetUpdateDraws() { + f() + } + + assert.Equal(t, "test_dir", ui.currentDir.GetName()) + + ui.table.Select(0, 0) + ui.keyPressed(tcell.NewEventKey(tcell.KeyRight, 'l', 0)) + ui.table.Select(1, 0) + ui.keyPressed(tcell.NewEventKey(tcell.KeyRight, 'l', 0)) + + assert.Equal(t, cwd, "test_dir/nested/subnested") +} + +func TestChangeCwdWithErr(t *testing.T) { + fin := testdir.CreateTestDir() + defer fin() + simScreen := testapp.CreateSimScreen(50, 50) + defer simScreen.Fini() + cwd := "" + + opt := func(ui *UI) { + ui.SetChangeCwdFn(func(p string) error { + cwd = p + return errors.New("failed") + }) + } + app := testapp.CreateMockedApp(true) + ui := CreateUI(app, simScreen, &bytes.Buffer{}, false, true, false, false, false, opt) + ui.done = make(chan struct{}) + err := ui.AnalyzePath("test_dir", nil) + assert.Nil(t, err) + + <-ui.done // wait for analyzer + + for _, f := range ui.app.(*testapp.MockedApp).GetUpdateDraws() { + f() + } + + assert.Equal(t, "test_dir", ui.currentDir.GetName()) + + ui.table.Select(0, 0) + ui.keyPressed(tcell.NewEventKey(tcell.KeyRight, 'l', 0)) + ui.table.Select(1, 0) + ui.keyPressed(tcell.NewEventKey(tcell.KeyRight, 'l', 0)) + + assert.Equal(t, cwd, "test_dir/nested/subnested") +} + func TestShowInfo(t *testing.T) { fin := testdir.CreateTestDir() defer fin() diff --git a/tui/show.go b/tui/show.go index a896940f2..7dcbd8cac 100644 --- a/tui/show.go +++ b/tui/show.go @@ -4,9 +4,11 @@ import ( "strconv" "strings" - "github.com/dundee/gdu/v5/build" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" + log "github.com/sirupsen/logrus" + + "github.com/dundee/gdu/v5/build" ) const helpText = ` [::b]up/down, k/j [white:black:-]Move cursor up/down @@ -48,6 +50,15 @@ func (ui *UI) showDir() { ) ui.currentDirPath = ui.currentDir.GetPath() + + if ui.changeCwdFn != nil { + err := ui.changeCwdFn(ui.currentDirPath) + if err != nil { + log.Printf("error setting cwd: %s", err.Error()) + } + log.Printf("changing cwd to %s", ui.currentDirPath) + } + ui.currentDirLabel.SetText("[::b] --- " + tview.Escape( strings.TrimPrefix(ui.currentDirPath, build.RootPathPrefix), diff --git a/tui/tui.go b/tui/tui.go index d82379fc0..a2186eb40 100644 --- a/tui/tui.go +++ b/tui/tui.go @@ -45,6 +45,7 @@ type UI struct { emptier func(fs.Item, fs.Item) error getter device.DevicesInfoGetter exec func(argv0 string, argv []string, envv []string) error + changeCwdFn func(string) error linkedItems fs.HardLinkedItems selectedTextColor tcell.Color selectedBackgroundColor tcell.Color @@ -179,6 +180,12 @@ func (ui *UI) SetCurrentItemNameMaxLen(len int) { ui.currentItemNameMaxLen = len } +// SetChangeCwdFn sets function that can be used to change current working dir +// during dir browsing +func (ui *UI) SetChangeCwdFn(fn func(string) error) { + ui.changeCwdFn = fn +} + // StartUILoop starts tview application func (ui *UI) StartUILoop() error { return ui.app.Run()