Skip to content

Commit

Permalink
Implemented base functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Amr Metwally committed Nov 11, 2022
1 parent 70dbaa7 commit ecfc2fa
Show file tree
Hide file tree
Showing 14 changed files with 466 additions and 7 deletions.
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
# Browser tab groups

Save and open **links** from the command line with ease. A tap group is a collection of links (urls) that belong together.
e.g `work` tap group would contain links for work.
e.g `uni` tap group would contain links for uni etc.

## Features

1. Group `urls` with a label
- use case: for work i want to quickly open `[Gitlab, Jira, Github, ...]`
- use case: for a given issue i want to quickly open its `[jira link, bitbucket pr, bitbucket branch, ...]`
- use case: for uni i want to quickly open `[Moodle, Web mailer, ...]`
1. Open a group of `urls` from the cli in the browser
1. Open a single `url` from a group of `urls`
- use case: for a given issue i saved its urls `[Bitbucket, Jira, Github, ...]` but want to quickly open only its `Jira link` without the rest of urls because i don't need them right now.
1. Remove a group of `urls`
- use case: after being done with a ticket. i want to remove all of its saved links

## Usage

1. `bt list` to list all saved tab groups
1. `bt add <tap group> <url>` to add the `url` to the tap group `tap group`
1. `bt open <tap group>` to open all `urls` in the tap group `tap group` in the browser
1. `bt open <tap group> <url matching string>` to open the url(s) that _fuzzy match_ `url matching string` in the browser
1. `br` will print the usage
1. `br list` to list all saved tab groups
1. `br add <tap group> <url>` to add the `url` to the tap group `tap group`
1. `br open <tap group>` to open all `urls` in the tap group `tap group` in the browser
1. `br open <tap group> <url matching string>` to open the url(s) that _fuzzy match_ `url matching string` in the browser

## Workflow looks like this

1. `br add work https://enerxess.atlassian.net/jira/your-work`
1. `br add work https://bitbucket.org/exseffi`
1. `br add uni https://webmail.tu-dortmund.de/roundcubemail/`
1. `br ls`

```
uni:
https://webmail.tu-dortmund.de/roundcubemail/
work:
https://enerxess.atlassian.net/jira/your-work
https://bitbucket.org/exseffi
```

1. `br open work` would open the two links under the `work` group in the browser
1. `br open work bit` would open the link for **bitbucket** because it uses `fuzzy finding` to filter for links based on the user's input
51 changes: 51 additions & 0 deletions browser/browser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package browser

import (
"os/exec"
"runtime"
)

type Browser interface {
//OpenLink opens a link in the browser
OpenLink(link string) error

//OpenLinks opens a link in the browser
OpenLinks(links []string) error
}

// browser is the internal implementation for the Browser interface
type browser struct {
}

// OpenLink opens a link in the browser
func (br *browser) OpenLink(link string) error {

var args []string
switch runtime.GOOS {
case "darwin":
args = []string{"open"}
case "windows":
args = []string{"cmd", "/c", "start"}
default:
args = []string{"xdg-open"}
}
cmd := exec.Command(args[0], append(args[1:], link)...)
return cmd.Start()
}

// OpenLinks opens all links in the browser
func (br *browser) OpenLinks(links []string) error {

for _, link := range links {
err := br.OpenLink(link)
if err != nil {
return err
}

}
return nil
}

func NewBrowser() Browser {
return &browser{}
}
32 changes: 32 additions & 0 deletions cmd/add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmd

import (
"io"
"os"

"github.com/magdyamr542/browser-tab-groups/configManager"
)

// Adding a new tap group
type AddCmd struct {
TapGroup string `arg:"" name:"tap group" help:"the tap group to add the url to"`
Url string `arg:"" name:"url" help:"the url to add"`
}

func (add *AddCmd) Run() error {
jsonCmg, err := configManager.NewJsonConfigManager()
if err != nil {
return err
}
return addUrlToTapGroup(os.Stdout, jsonCmg, add.TapGroup, add.Url)
}

// addUrlToTapGroup adds the given url to the given tap group
func addUrlToTapGroup(outputW io.Writer, cm configManager.ConfigManager, tapGroup, url string) error {
err := cm.AddUrl(url, tapGroup)
if err != nil {
return err
}
outputW.Write([]byte("url added"))
return nil
}
43 changes: 43 additions & 0 deletions cmd/ls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cmd

import (
"fmt"
"io"
"os"

"github.com/magdyamr542/browser-tab-groups/configManager"
)

// Listing all tap groups with their urls
type LsCmd struct{}

func (ls *LsCmd) Run() error {

jsonCmg, err := configManager.NewJsonConfigManager()
if err != nil {
return err
}
return listTapGroups(os.Stdout, jsonCmg)
}

// listTapGroups lists all tap groups
func listTapGroups(outputW io.Writer, cm configManager.ConfigManager) error {
cfg, err := cm.GetConfig()
if err != nil {
return err
}

i := 0
for groupName, urls := range cfg {
entry := fmt.Sprintf("%v:\n", groupName)
outputW.Write([]byte(entry))
for i := range urls {
outputW.Write([]byte(fmt.Sprintf(" %v\n", urls[i])))
}
i += 1
if i < len(cfg) {
outputW.Write([]byte("\n"))
}
}
return nil
}
52 changes: 52 additions & 0 deletions cmd/open.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cmd

import (
"errors"
"io"
"os"
"strings"

"github.com/magdyamr542/browser-tab-groups/browser"
"github.com/magdyamr542/browser-tab-groups/configManager"
"github.com/magdyamr542/browser-tab-groups/helpers"

"github.com/lithammer/fuzzysearch/fuzzy"
)

// Adding a new tap group
type OpenCmd struct {
TapGroup string `arg:"" name:"tap group" help:"the tap group to add the url to"`
UrlLike string `arg:"" optional:"" name:"url part" help:"a part of the url to be use with fuzzy matching"`
}

func (open *OpenCmd) Run() error {
jsonCmg, err := configManager.NewJsonConfigManager()
if err != nil {
return err
}
return openTapGroup(os.Stdout, open.TapGroup, open.UrlLike, jsonCmg, browser.NewBrowser())
}

// AddUrlToTapGroup adds the given url to the given tap group
func openTapGroup(outputW io.Writer, tapGroup string, urlLike string, cm configManager.ConfigManager, br browser.Browser) error {
urls, err := cm.GetUrls(tapGroup)
if err != nil {
return err
}
if len(urls) == 0 {
return errors.New("the given tap group does not have urls")
}

if len(strings.TrimSpace(urlLike)) > 0 {
urlLikeLower := strings.ToLower(urlLike)
urls = helpers.Filter(urls, func(url string) bool {
return fuzzy.Match(urlLikeLower, strings.ToLower(url))
})

if len(urls) == 0 {
return errors.New("no matches found in the given tap group")
}
}

return br.OpenLinks(urls)
}
32 changes: 32 additions & 0 deletions cmd/rm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmd

import (
"io"
"os"

"github.com/magdyamr542/browser-tab-groups/configManager"
)

// Removing a tap group
type RmCmd struct {
TapGroup string `arg:"" name:"tap group" help:"the tap group to remove"`
}

func (rm *RmCmd) Run() error {

jsonCmg, err := configManager.NewJsonConfigManager()
if err != nil {
return err
}
return removeTapGroup(os.Stdout, jsonCmg, rm.TapGroup)
}

// removeTapGroup removes a saved tap group
func removeTapGroup(outputW io.Writer, cm configManager.ConfigManager, tapGroup string) error {
err := cm.RemoveTapGroup(tapGroup)
if err != nil {
return err
}
outputW.Write([]byte("removed"))
return nil
}
15 changes: 15 additions & 0 deletions configManager/configManager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package configManager

type ConfigManager interface {
//GetConfig gets the config instance. this should be a map from a tap group to the list of urls
GetConfig() (map[string][]string, error)

// AddUrl adds the given url to the given tap group. the tap group is created if it does not exist
AddUrl(url string, tapGroup string) error

// GetUrls gets the urls for the given tap group
GetUrls(tapGroup string) ([]string, error)

// RemoveTapGroup removes all urls saved in the given tap group
RemoveTapGroup(tapGroup string) error
}
Loading

0 comments on commit ecfc2fa

Please sign in to comment.