diff --git a/pkg/app/app.go b/pkg/app/app.go index cd5c2f4..9c8333b 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1,7 +1,6 @@ package app import ( - "errors" "io" "io/ioutil" "os" @@ -105,10 +104,6 @@ func NewApp(config config.AppConfigurer) (*App, error) { return app, err } - if err := app.setupPackage(); err != nil { - return app, err - } - app.NpmManager, err = commands.NewNpmManager(app.Log, app.OSCommand, app.Tr, app.Config) if err != nil { return app, err @@ -121,33 +116,6 @@ func NewApp(config config.AppConfigurer) (*App, error) { return app, nil } -func (app *App) setupPackage() error { - // ensure we have a package.json file here or in an ancestor directory - // if there's not, pick the first one from state or return an error - dir, err := os.Getwd() - if err != nil { - return err - } - for { - if commands.FileExists("package.json") { - return nil - } - - if err := os.Chdir(".."); err != nil { - return err - } - - newDir, err := os.Getwd() - if err != nil { - return err - } - if newDir == dir { - return errors.New("must start lazynpm in an npm package") - } - dir = newDir - } -} - func (app *App) Run() error { err := app.Gui.RunWithSubprocesses() return err diff --git a/pkg/commands/dependency.go b/pkg/commands/dependency.go new file mode 100644 index 0000000..d0f9841 --- /dev/null +++ b/pkg/commands/dependency.go @@ -0,0 +1,6 @@ +package commands + +type Dependency struct { + Name string + Version string +} diff --git a/pkg/commands/npm_manager.go b/pkg/commands/npm_manager.go index e783cf7..d54a4cc 100644 --- a/pkg/commands/npm_manager.go +++ b/pkg/commands/npm_manager.go @@ -146,3 +146,28 @@ func (m *NpmManager) GetPackages(paths []string) ([]*Package, error) { } return pkgs, nil } + +func (m *NpmManager) ChdirToPackageRoot() (bool, error) { + dir, err := os.Getwd() + if err != nil { + return false, err + } + for { + if FileExists("package.json") { + return true, nil + } + + if err := os.Chdir(".."); err != nil { + return false, err + } + + newDir, err := os.Getwd() + if err != nil { + return false, err + } + if newDir == dir { + return false, nil + } + dir = newDir + } +} diff --git a/pkg/commands/package.go b/pkg/commands/package.go index b55d129..6aa0779 100644 --- a/pkg/commands/package.go +++ b/pkg/commands/package.go @@ -1,8 +1,10 @@ package commands -import "encoding/json" - -// golang doesn't support union types, but fields like 'author' and 'repository' can actually be strings or objects so we'll need to keep that in mind when parsing +import ( + "encoding/json" + "sort" + "strings" +) type PackageConfigInput struct { Name string `json:"name"` @@ -88,3 +90,21 @@ type PackageConfig struct { OptionalDependencies map[string]string BundleDependencies bool } + +func (p *Package) SortedDeps() []*Dependency { + deps := make([]*Dependency, 0, len(p.Config.Dependencies)) + for name, version := range p.Config.Dependencies { + deps = append(deps, &Dependency{Name: name, Version: version}) + } + sort.Slice(deps, func(i, j int) bool { return strings.Compare(deps[i].Name, deps[j].Name) > 0 }) + return deps +} + +func (p *Package) SortedScripts() []*Script { + scripts := make([]*Script, 0, len(p.Config.Scripts)) + for name, command := range p.Config.Scripts { + scripts = append(scripts, &Script{Name: name, Command: command}) + } + sort.Slice(scripts, func(i, j int) bool { return strings.Compare(scripts[i].Name, scripts[j].Name) > 0 }) + return scripts +} diff --git a/pkg/commands/script.go b/pkg/commands/script.go new file mode 100644 index 0000000..17e8234 --- /dev/null +++ b/pkg/commands/script.go @@ -0,0 +1,6 @@ +package commands + +type Script struct { + Name string + Command string +} diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index ef9623e..0e10b6a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -40,8 +40,8 @@ type AppConfigurer interface { WriteToUserConfig(string, interface{}) error SaveAppState() error LoadAppState() error - SetIsNewRepo(bool) - GetIsNewRepo() bool + SetIsNewPackage(bool) + GetIsNewPackage() bool } // NewAppConfig makes a new app config @@ -75,13 +75,13 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg return appConfig, nil } -// GetIsNewRepo returns known repo boolean -func (c *AppConfig) GetIsNewRepo() bool { +// GetIsNewPackage returns known repo boolean +func (c *AppConfig) GetIsNewPackage() bool { return c.IsNewPackage } -// SetIsNewRepo set if the current repo is known -func (c *AppConfig) SetIsNewRepo(isNew bool) { +// SetIsNewPackage set if the current repo is known +func (c *AppConfig) SetIsNewPackage(isNew bool) { c.IsNewPackage = isNew } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 26b5e84..5c7428f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -134,6 +134,7 @@ type guiState struct { PrevMainHeight int OldInformation string StartupStage int // one of INITIAL and COMPLETE. Allows us to not load everything at once + CurrentPackageIdx int } func (gui *Gui) resetState() { @@ -306,14 +307,26 @@ func (gui *Gui) loadNewRepo() error { // so that appears in the packages view next time we open the program in another package func (gui *Gui) updateRecentRepoList() error { recentPackages := gui.Config.GetAppState().RecentPackages - currentRepo, err := os.Getwd() + ok, err := gui.NpmManager.ChdirToPackageRoot() if err != nil { return err } - isNew, recentPackages := newRecentPackagesList(recentPackages, currentRepo) - gui.Config.SetIsNewRepo(isNew) - gui.Config.GetAppState().RecentPackages = recentPackages - return gui.Config.SaveAppState() + if ok { + currentPackagePath, err := os.Getwd() + if err != nil { + return err + } + isNew, recentPackages := newRecentPackagesList(recentPackages, currentPackagePath) + gui.Config.SetIsNewPackage(isNew) + gui.Config.GetAppState().RecentPackages = recentPackages + return gui.Config.SaveAppState() + } + + if len(recentPackages) > 0 { + // TODO: ensure this actually contains a package.json file (meaning it won't be filtered out) + return os.Chdir(recentPackages[0]) + } + return errors.New("Must open lazynpm in an npm package") } // newRecentPackagesList returns a new repo list with a new entry but only when it doesn't exist yet diff --git a/pkg/gui/list_view.go b/pkg/gui/list_view.go index d481e01..dd807df 100644 --- a/pkg/gui/list_view.go +++ b/pkg/gui/list_view.go @@ -27,18 +27,23 @@ func (lv *listView) handleLineChange(change int) error { return nil } + view, err := lv.gui.g.View(lv.viewName) + if err != nil { + return err + } + lv.gui.changeSelectedLine(lv.getSelectedLineIdxPtr(), lv.getItemsLength(), change) + view.FocusPoint(0, *lv.getSelectedLineIdxPtr()) if lv.rendersToMainView { if err := lv.gui.resetOrigin(lv.gui.getMainView()); err != nil { return err } + if err := lv.gui.resetOrigin(lv.gui.getSecondaryView()); err != nil { + return err + } } - view, err := lv.gui.g.View(lv.viewName) - if err != nil { - return err - } return lv.handleItemSelect(lv.gui.g, view) } @@ -95,6 +100,9 @@ func (lv *listView) handleClick(g *gocui.Gui, v *gocui.View) error { if err := lv.gui.resetOrigin(lv.gui.getMainView()); err != nil { return err } + if err := lv.gui.resetOrigin(lv.gui.getSecondaryView()); err != nil { + return err + } } prevViewName := lv.gui.currentViewName() diff --git a/pkg/gui/packages_panel.go b/pkg/gui/packages_panel.go index b18a7f0..38954e6 100644 --- a/pkg/gui/packages_panel.go +++ b/pkg/gui/packages_panel.go @@ -16,25 +16,11 @@ func (gui *Gui) getSelectedPackage() *commands.Package { } func (gui *Gui) handlePackageSelect(g *gocui.Gui, v *gocui.View) error { - return nil -} - -func (gui *Gui) selectPackage() error { - gui.getPackagesView().FocusPoint(0, gui.State.Panels.Packages.SelectedLine) - pkg := gui.getSelectedPackage() if pkg == nil { gui.getMainView().Title = "" return gui.newStringTask("main", gui.Tr.SLocalize("NoChangedPackages")) } - - if err := gui.resetOrigin(gui.getMainView()); err != nil { - return err - } - if err := gui.resetOrigin(gui.getSecondaryView()); err != nil { - return err - } - return nil } @@ -51,12 +37,25 @@ func (gui *Gui) refreshPackages() error { gui.g.Update(func(g *gocui.Gui) error { displayStrings := presentation.GetPackageListDisplayStrings(gui.State.Packages) gui.renderDisplayStrings(packagesView, displayStrings) + + displayStrings = presentation.GetDependencyListDisplayStrings(gui.currentPackage().SortedDeps()) + gui.renderDisplayStrings(gui.getDepsView(), displayStrings) + + displayStrings = presentation.GetScriptListDisplayStrings(gui.currentPackage().SortedScripts()) + gui.renderDisplayStrings(gui.getScriptsView(), displayStrings) return nil }) return nil } +func (gui *Gui) currentPackage() *commands.Package { + if len(gui.State.Packages) == 0 { + panic("need at least one package") + } + return gui.State.Packages[0] +} + // specific functions func (gui *Gui) refreshStatePackages() error { diff --git a/pkg/gui/presentation/dependencies.go b/pkg/gui/presentation/dependencies.go new file mode 100644 index 0000000..16726a5 --- /dev/null +++ b/pkg/gui/presentation/dependencies.go @@ -0,0 +1,19 @@ +package presentation + +import ( + "github.com/jesseduffield/lazynpm/pkg/commands" +) + +func GetDependencyListDisplayStrings(dependencies []*commands.Dependency) [][]string { + lines := make([][]string, len(dependencies)) + + for i := range dependencies { + lines[i] = getDepDisplayStrings(dependencies[i]) + } + + return lines +} + +func getDepDisplayStrings(p *commands.Dependency) []string { + return []string{p.Name, p.Version} +} diff --git a/pkg/gui/presentation/packages.go b/pkg/gui/presentation/packages.go index 7050743..c2f5972 100644 --- a/pkg/gui/presentation/packages.go +++ b/pkg/gui/presentation/packages.go @@ -11,13 +11,13 @@ func GetPackageListDisplayStrings(packages []*commands.Package) [][]string { lines := make([][]string, len(packages)) for i := range packages { - lines[i] = getFileDisplayStrings(packages[i]) + lines[i] = getPackageDisplayStrings(packages[i]) } return lines } -func getFileDisplayStrings(p *commands.Package) []string { +func getPackageDisplayStrings(p *commands.Package) []string { line := utils.ColoredString(p.Config.Name, theme.DefaultTextColor) if p.Linked { line += utils.ColoredString(" (linked)", color.FgCyan) diff --git a/pkg/gui/presentation/scripts.go b/pkg/gui/presentation/scripts.go new file mode 100644 index 0000000..2f91ef7 --- /dev/null +++ b/pkg/gui/presentation/scripts.go @@ -0,0 +1,19 @@ +package presentation + +import ( + "github.com/jesseduffield/lazynpm/pkg/commands" +) + +func GetScriptListDisplayStrings(scripts []*commands.Script) [][]string { + lines := make([][]string, len(scripts)) + + for i := range scripts { + lines[i] = getScriptDisplayStrings(scripts[i]) + } + + return lines +} + +func getScriptDisplayStrings(p *commands.Script) []string { + return []string{p.Name, p.Command} +} diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 58d4446..34d2e00 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -10,7 +10,7 @@ import ( "github.com/spkg/bom" ) -var cyclableViews = []string{"status", "packages", "depdencies", "scripts"} +var cyclableViews = []string{"status", "packages", "deps", "scripts"} func intArrToMap(arr []int) map[int]bool { output := map[int]bool{} @@ -97,6 +97,10 @@ func (gui *Gui) newLineFocused(g *gocui.Gui, v *gocui.View) error { return gui.handleStatusSelect(g, v) case "packages": return gui.handlePackageSelect(g, v) + case "deps": + return gui.handlePackageSelect(g, v) + case "scripts": + return gui.handlePackageSelect(g, v) case "main": v.Highlight = false return nil