From 357761313b00cb5799b2971631c4adfb2daaa98e Mon Sep 17 00:00:00 2001 From: Ibrahim Serdar Acikgoz Date: Wed, 5 Dec 2018 01:24:48 +0300 Subject: added sorting --- README.md | 6 ++--- pkg/git/repository-sort.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++ pkg/git/repository.go | 10 ++++++++ pkg/gui/gui-util.go | 25 ++++++++++++++++++++ pkg/gui/keybindings.go | 16 +++++++++++++ pkg/gui/mainview.go | 2 +- 6 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 pkg/git/repository-sort.go diff --git a/README.md b/README.md index ba70ce8..0d42830 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Build Status](https://travis-ci.com/isacikgoz/gitbatch.svg?branch=master)](https://travis-ci.com/isacikgoz/gitbatch) [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/isacikgoz/gitbatch)](https://goreportcard.com/report/github.com/isacikgoz/gitbatch) ## gitbatch -Aim of this tool to make your local repositories synchronized with remotes easily. Since my daily work is tied to many repositories I often end up walking on many directories and manually pulling updates etc. To make this routine more elegant, I created a simple tool to handle this job. I really enjoy working on this project and I hope it will be a useful tool. +Aim of this tool to make your local repositories synchronized with remotes easily. Inspired from lazygit and I build this according to my needs; Since my daily work is tied to many repositories I often end up walking on many directories and manually pulling updates etc. To make this routine faster, I created a simple tool to handle this job. I really enjoy working on this project and I hope it will be a useful tool. **Disclaimer** - Authentication required repositories are **not supported** using ssh is recommended if you need to authenticate to fetch/pull @@ -77,8 +77,8 @@ run the `gitbatch` command from the parent of your git repositories. For start-u ## Further goals - add testing - select all feature -- arrange repositories to an order e.g. alphabetic, last modified, etc. -- shift keys, i.e. **s** for iterate **alt + s** for reverse iteration (partially implemented) +- arrange repositories to an order e.g. alphabetic, last modified, etc. ✔ +- shift keys, i.e. **s** for iterate **alt + s** for reverse iteration ✔ - recursive repository search from the filesystem - full src-d/go-git integration (*having some performance issues*) - implement config file to pre-define repo locations or some settings diff --git a/pkg/git/repository-sort.go b/pkg/git/repository-sort.go new file mode 100644 index 0000000..04cd9e7 --- /dev/null +++ b/pkg/git/repository-sort.go @@ -0,0 +1,59 @@ +package git + +import ( + "unicode" +) + +// Alphabetical slice is the re-ordered *RepoEntity slice that sorted according +// to alphabetical order (A-Z) +type Alphabetical []*RepoEntity + +// Len is the interface implementation for Alphabetical sorting function +func (s Alphabetical) Len() int { return len(s) } + +// Swap is the interface implementation for Alphabetical sorting function +func (s Alphabetical) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// Less is the interface implementation for Alphabetical sorting function +func (s Alphabetical) Less(i, j int) bool { + iRunes := []rune(s[i].Name) + jRunes := []rune(s[j].Name) + + max := len(iRunes) + if max > len(jRunes) { + max = len(jRunes) + } + + for idx := 0; idx < max; idx++ { + ir := iRunes[idx] + jr := jRunes[idx] + + lir := unicode.ToLower(ir) + ljr := unicode.ToLower(jr) + + if lir != ljr { + return lir < ljr + } + + // the lowercase runes are the same, so compare the original + if ir != jr { + return ir < jr + } + } + return false +} + +// LastModified slice is the re-ordered *RepoEntity slice that sorted according +// to last modified date of the repository directory +type LastModified []*RepoEntity + +// Len is the interface implementation for LastModified sorting function +func (s LastModified) Len() int { return len(s) } + +// Swap is the interface implementation for LastModified sorting function +func (s LastModified) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// Less is the interface implementation for LastModified sorting function +func (s LastModified) Less(i, j int) bool { + return s[i].ModTime.Unix() > s[j].ModTime.Unix() +} diff --git a/pkg/git/repository.go b/pkg/git/repository.go index 73aebdf..6918371 100644 --- a/pkg/git/repository.go +++ b/pkg/git/repository.go @@ -2,6 +2,7 @@ package git import ( "errors" + "time" "os" "github.com/isacikgoz/gitbatch/pkg/helpers" @@ -16,6 +17,7 @@ type RepoEntity struct { RepoID string Name string AbsPath string + ModTime time.Time Repository git.Repository Branch *Branch Branches []*Branch @@ -65,6 +67,7 @@ func InitializeRepository(directory string) (entity *RepoEntity, err error) { entity = &RepoEntity{RepoID: helpers.RandomString(8), Name: fileInfo.Name(), AbsPath: directory, + ModTime: fileInfo.ModTime(), Repository: *r, State: Available, } @@ -156,11 +159,18 @@ func (entity *RepoEntity) Merge() error { // fetch/pull/merge operations func (entity *RepoEntity) Refresh() error { var err error + // error can be ignored since the file already exists when app is loading + file, _ := os.Open(entity.AbsPath) + fileInfo, err := file.Stat() + if err != nil { + return err + } r, err := git.PlainOpen(entity.AbsPath) if err != nil { return err } entity.Repository = *r + entity.ModTime = fileInfo.ModTime() if err := entity.loadLocalBranches(); err != nil { return err } diff --git a/pkg/gui/gui-util.go b/pkg/gui/gui-util.go index c09ae6c..d3f0934 100644 --- a/pkg/gui/gui-util.go +++ b/pkg/gui/gui-util.go @@ -1,6 +1,8 @@ package gui import ( + "sort" + "github.com/isacikgoz/gitbatch/pkg/git" "github.com/isacikgoz/gitbatch/pkg/helpers" "github.com/jroimartin/gocui" @@ -107,3 +109,26 @@ func writeRightHandSide(v *gocui.View, text string, cx, cy int) error { v.SetCursor(cx, cy) return nil } + +// sortByName sorts the repositories by A to Z order +func (gui *Gui) sortByName(g *gocui.Gui, v *gocui.View) error { + sort.Sort(git.Alphabetical(gui.State.Repositories)) + gui.refreshAfterSort(g) + return nil +} + +// sortByMod sorts the repositories according to last modifed date +// the top element will be the last modified +func (gui *Gui) sortByMod(g *gocui.Gui, v *gocui.View) error { + sort.Sort(git.LastModified(gui.State.Repositories)) + gui.refreshAfterSort(g) + return nil +} + +// utility function that refreshes main and side views after that +func (gui *Gui) refreshAfterSort(g *gocui.Gui) error { + gui.refreshMain(g) + entity := gui.getSelectedRepository() + gui.refreshViews(g, entity) + return nil +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index f224bc3..3a96221 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -149,6 +149,22 @@ func (gui *Gui) generateKeybindings() error { Display: "space", Description: "Add to queue", Vital: true, + }, { + View: mainViewFeature.Name, + Key: 'n', + Modifier: gocui.ModNone, + Handler: gui.sortByName, + Display: "n", + Description: "Sort repositories by Name", + Vital: false, + }, { + View: mainViewFeature.Name, + Key: 'm', + Modifier: gocui.ModNone, + Handler: gui.sortByMod, + Display: "m", + Description: "Sort repositories by Modification date", + Vital: false, }, { View: commitDiffViewFeature.Name, Key: 'c', diff --git a/pkg/gui/mainview.go b/pkg/gui/mainview.go index e9bd1f3..6911c69 100644 --- a/pkg/gui/mainview.go +++ b/pkg/gui/mainview.go @@ -93,7 +93,7 @@ func (gui *Gui) getSelectedRepository() *git.RepoEntity { return gui.State.Repositories[cy+oy] } -// marking repostiry is simply adding the repostirory into the queue. the +// marking repository is simply adding the repostirory into the queue. the // function does take its current state into account before adding it func (gui *Gui) markRepository(g *gocui.Gui, v *gocui.View) error { r := gui.getSelectedRepository() -- cgit v1.2.3