github.com/wtfutil/wtf@v0.43.0/modules/git/widget.go (about)

     1  package git
     2  
     3  import (
     4  	"log"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/gdamore/tcell/v2"
     9  	"github.com/rivo/tview"
    10  	"github.com/wtfutil/wtf/utils"
    11  	"github.com/wtfutil/wtf/view"
    12  )
    13  
    14  const (
    15  	modalHeight = 7
    16  	modalWidth  = 80
    17  	offscreen   = -1000
    18  )
    19  
    20  type Widget struct {
    21  	view.MultiSourceWidget
    22  	view.TextWidget
    23  
    24  	GitRepos []*GitRepo
    25  
    26  	pages    *tview.Pages
    27  	settings *Settings
    28  	tviewApp *tview.Application
    29  }
    30  
    31  func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget {
    32  	widget := Widget{
    33  		MultiSourceWidget: view.NewMultiSourceWidget(settings.Common, "repository", "repositories"),
    34  		TextWidget:        view.NewTextWidget(tviewApp, redrawChan, pages, settings.Common),
    35  
    36  		tviewApp: tviewApp,
    37  		pages:    pages,
    38  		settings: settings,
    39  	}
    40  
    41  	widget.initializeKeyboardControls()
    42  
    43  	widget.SetDisplayFunction(widget.display)
    44  
    45  	return &widget
    46  }
    47  
    48  /* -------------------- Exported Functions -------------------- */
    49  
    50  func (widget *Widget) Checkout() {
    51  	form := widget.modalForm("Branch to checkout:", "")
    52  
    53  	checkoutFctn := func() {
    54  		text := form.GetFormItem(0).(*tview.InputField).GetText()
    55  		repoToCheckout := widget.GitRepos[widget.Idx]
    56  		repoToCheckout.checkout(text)
    57  		widget.pages.RemovePage("modal")
    58  		widget.tviewApp.SetFocus(widget.View)
    59  		widget.display()
    60  		widget.Refresh()
    61  	}
    62  
    63  	widget.addButtons(form, checkoutFctn)
    64  	widget.modalFocus(form)
    65  }
    66  
    67  func (widget *Widget) Pull() {
    68  	repoToPull := widget.GitRepos[widget.Idx]
    69  	repoToPull.pull()
    70  	widget.Refresh()
    71  
    72  }
    73  
    74  func (widget *Widget) Refresh() {
    75  	repoPaths := utils.ToStrs(widget.settings.repositories)
    76  
    77  	widget.GitRepos = widget.gitRepos(repoPaths)
    78  
    79  	widget.display()
    80  }
    81  
    82  /* -------------------- Unexported Functions -------------------- */
    83  
    84  func (widget *Widget) addCheckoutButton(form *tview.Form, fctn func()) {
    85  	form.AddButton("Checkout", fctn)
    86  }
    87  
    88  func (widget *Widget) addButtons(form *tview.Form, checkoutFctn func()) {
    89  	widget.addCheckoutButton(form, checkoutFctn)
    90  	widget.addCancelButton(form)
    91  }
    92  
    93  func (widget *Widget) addCancelButton(form *tview.Form) {
    94  	cancelFn := func() {
    95  		widget.pages.RemovePage("modal")
    96  		widget.tviewApp.SetFocus(widget.View)
    97  		widget.display()
    98  	}
    99  
   100  	form.AddButton("Cancel", cancelFn)
   101  	form.SetCancelFunc(cancelFn)
   102  }
   103  
   104  func (widget *Widget) modalFocus(form *tview.Form) {
   105  	frame := widget.modalFrame(form)
   106  	widget.pages.AddPage("modal", frame, false, true)
   107  	widget.tviewApp.SetFocus(frame)
   108  }
   109  
   110  func (widget *Widget) modalForm(lbl, text string) *tview.Form {
   111  	form := tview.NewForm()
   112  	form.SetButtonsAlign(tview.AlignCenter)
   113  	form.SetButtonTextColor(tview.Styles.PrimaryTextColor)
   114  
   115  	form.AddInputField(lbl, text, 60, nil, nil)
   116  
   117  	return form
   118  }
   119  
   120  func (widget *Widget) modalFrame(form *tview.Form) *tview.Frame {
   121  	frame := tview.NewFrame(form)
   122  	frame.SetBorders(0, 0, 0, 0, 0, 0)
   123  	frame.SetRect(offscreen, offscreen, modalWidth, modalHeight)
   124  	frame.SetBorder(true)
   125  	frame.SetBorders(1, 1, 0, 0, 1, 1)
   126  
   127  	drawFunc := func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {
   128  		w, h := screen.Size()
   129  		frame.SetRect((w/2)-(width/2), (h/2)-(height/2), width, height)
   130  		return x, y, width, height
   131  	}
   132  
   133  	frame.SetDrawFunc(drawFunc)
   134  
   135  	return frame
   136  }
   137  
   138  func (widget *Widget) currentData() *GitRepo {
   139  	if len(widget.GitRepos) == 0 {
   140  		return nil
   141  	}
   142  
   143  	if widget.Idx < 0 || widget.Idx >= len(widget.GitRepos) {
   144  		return nil
   145  	}
   146  
   147  	return widget.GitRepos[widget.Idx]
   148  }
   149  
   150  func (widget *Widget) gitRepos(repoPaths []string) []*GitRepo {
   151  	repos := []*GitRepo{}
   152  
   153  	for _, repoPath := range repoPaths {
   154  		if strings.HasSuffix(repoPath, string(os.PathSeparator)) {
   155  			repos = append(repos, widget.findGitRepositories(make([]*GitRepo, 0), repoPath)...)
   156  
   157  		} else {
   158  			repo := NewGitRepo(
   159  				repoPath,
   160  				widget.settings.commitCount,
   161  				widget.settings.commitFormat,
   162  				widget.settings.dateFormat,
   163  			)
   164  
   165  			repos = append(repos, repo)
   166  		}
   167  	}
   168  
   169  	return repos
   170  }
   171  
   172  func (widget *Widget) findGitRepositories(repositories []*GitRepo, directory string) []*GitRepo {
   173  	directory = strings.TrimSuffix(directory, string(os.PathSeparator))
   174  
   175  	files, err := os.ReadDir(directory)
   176  	if err != nil {
   177  		log.Fatal(err)
   178  	}
   179  
   180  	var path string
   181  
   182  	for _, file := range files {
   183  		if file.IsDir() {
   184  			path = directory + string(os.PathSeparator) + file.Name()
   185  
   186  			if file.Name() == ".git" {
   187  				path = strings.TrimSuffix(path, string(os.PathSeparator)+".git")
   188  
   189  				repo := NewGitRepo(
   190  					path,
   191  					widget.settings.commitCount,
   192  					widget.settings.commitFormat,
   193  					widget.settings.dateFormat,
   194  				)
   195  
   196  				repositories = append(repositories, repo)
   197  				continue
   198  			}
   199  			if file.Name() == "vendor" || file.Name() == "node_modules" {
   200  				continue
   201  			}
   202  			repositories = widget.findGitRepositories(repositories, path)
   203  		}
   204  	}
   205  
   206  	return repositories
   207  }