Merge pull request #18 from aditya-K2/buffsearch
Implementing Simple Buffer Searching
This commit is contained in:
commit
f6800b0361
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
gomp
|
gomp
|
||||||
.idea
|
.idea
|
||||||
*.jpg
|
*.jpg
|
||||||
|
e.go
|
||||||
|
@ -7,9 +7,6 @@ import (
|
|||||||
"github.com/fhs/gompd/mpd"
|
"github.com/fhs/gompd/mpd"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aditya-K2/gomp/utils"
|
|
||||||
"github.com/aditya-K2/tview"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,7 +15,7 @@ var (
|
|||||||
NotificationServer interface {
|
NotificationServer interface {
|
||||||
Send(string)
|
Send(string)
|
||||||
}
|
}
|
||||||
WHITE_AND_BOLD string = "[#ffffff::b]"
|
WHITE_AND_BOLD string = "[white::b]"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetConnection(c *mpd.Client) {
|
func SetConnection(c *mpd.Client) {
|
||||||
@ -39,22 +36,6 @@ func TogglePlayBack() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdatePlaylist(inputTable *tview.Table) {
|
|
||||||
_playlistAttr, _ := CONN.PlaylistInfo(-1, -1)
|
|
||||||
|
|
||||||
inputTable.Clear()
|
|
||||||
for i, j := range _playlistAttr {
|
|
||||||
_, _, w, _ := inputTable.GetInnerRect()
|
|
||||||
if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" {
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3)))
|
|
||||||
} else {
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+j["Title"], w/3)))
|
|
||||||
inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+j["Artist"], w/3)))
|
|
||||||
inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The GenerateContentSlice returns a slice of the content to be displayed on the Search View. The Slice is generated
|
// The GenerateContentSlice returns a slice of the content to be displayed on the Search View. The Slice is generated
|
||||||
// because the random nature of maps as they return values randomly hence the draw function keeps changing the order
|
// because the random nature of maps as they return values randomly hence the draw function keeps changing the order
|
||||||
// in which the results appear.
|
// in which the results appear.
|
||||||
@ -99,70 +80,6 @@ func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
|
|||||||
return ContentSlice, nil
|
return ContentSlice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called
|
|
||||||
// Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main
|
|
||||||
// function this will also help in persisting the Search Results.
|
|
||||||
func UpdateSearchView(inputTable *tview.Table, c []interface{}) {
|
|
||||||
inputTable.Clear()
|
|
||||||
_, _, width, _ := inputTable.GetInnerRect()
|
|
||||||
for i, content := range c {
|
|
||||||
switch content.(type) {
|
|
||||||
case [3]string:
|
|
||||||
{
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([3]string)[0], width/3)))
|
|
||||||
inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([3]string)[1], width/3)))
|
|
||||||
inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString("[yellow]"+content.([3]string)[2], width/3)))
|
|
||||||
}
|
|
||||||
case [2]string:
|
|
||||||
{
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([2]string)[0], width/3)))
|
|
||||||
inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([2]string)[1], width/3)))
|
|
||||||
}
|
|
||||||
case string:
|
|
||||||
{
|
|
||||||
b := content.(string)
|
|
||||||
if !strings.HasPrefix(b, WHITE_AND_BOLD) {
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell("[green]"+content.(string)))
|
|
||||||
} else {
|
|
||||||
inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Update(f []FileNode, inputTable *tview.Table) {
|
|
||||||
inputTable.Clear()
|
|
||||||
for i, j := range f {
|
|
||||||
if len(j.Children) == 0 {
|
|
||||||
_songAttributes, err := CONN.ListAllInfo(j.AbsolutePath)
|
|
||||||
if err == nil && _songAttributes[0]["Title"] != "" {
|
|
||||||
_, _, w, _ := inputTable.GetInnerRect()
|
|
||||||
inputTable.SetCell(i, 0,
|
|
||||||
tview.NewTableCell("[green]"+utils.GetFormattedString(_songAttributes[0]["Title"], w/3)).
|
|
||||||
SetAlign(tview.AlignLeft))
|
|
||||||
|
|
||||||
inputTable.SetCell(i, 1,
|
|
||||||
tview.NewTableCell("[magenta]"+utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)).
|
|
||||||
SetAlign(tview.AlignLeft))
|
|
||||||
|
|
||||||
inputTable.SetCell(i, 2,
|
|
||||||
tview.NewTableCell("[yellow]"+_songAttributes[0]["Album"]).
|
|
||||||
SetAlign(tview.AlignLeft))
|
|
||||||
|
|
||||||
} else if _songAttributes[0]["Title"] == "" {
|
|
||||||
inputTable.SetCell(i, 0,
|
|
||||||
tview.NewTableCell("[blue]"+j.Path).
|
|
||||||
SetAlign(tview.AlignLeft))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inputTable.SetCell(i, 0,
|
|
||||||
tview.NewTableCell("[yellow::b]"+j.Path).
|
|
||||||
SetAlign(tview.AlignLeft))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateArtistTree Artist Tree is a map of Artist to their Album Map
|
// GenerateArtistTree Artist Tree is a map of Artist to their Album Map
|
||||||
// Album Tree is a map of the tracks in that particular album.
|
// Album Tree is a map of the tracks in that particular album.
|
||||||
func GenerateArtistTree() (map[string]map[string]map[string]string, error) {
|
func GenerateArtistTree() (map[string]map[string]map[string]string, error) {
|
||||||
|
@ -3,6 +3,8 @@ package client
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fhs/gompd/mpd"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileNode struct {
|
type FileNode struct {
|
||||||
@ -10,13 +12,28 @@ type FileNode struct {
|
|||||||
Path string
|
Path string
|
||||||
Parent *FileNode
|
Parent *FileNode
|
||||||
AbsolutePath string
|
AbsolutePath string
|
||||||
|
Title string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileNode) AddChildren(path string) {
|
// Source Interface For Fuzzy Searching.
|
||||||
|
type FileNodes []FileNode
|
||||||
|
|
||||||
|
func (f FileNodes) String(i int) string {
|
||||||
|
if len(f[i].Children) == 0 {
|
||||||
|
return f[i].Title
|
||||||
|
}
|
||||||
|
return f[i].Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileNodes) Len() int {
|
||||||
|
return len(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileNode) AddChildren(path string, title string) {
|
||||||
if f.Path != "" {
|
if f.Path != "" {
|
||||||
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path})
|
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path, Title: title})
|
||||||
} else {
|
} else {
|
||||||
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + path})
|
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + path, Title: title})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,14 +42,14 @@ func (f *FileNode) AddChildNode(m FileNode) {
|
|||||||
f.Children = append(f.Children, m)
|
f.Children = append(f.Children, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateDirectoryTree(path []string) *FileNode {
|
func GenerateDirectoryTree(path []mpd.Attrs) *FileNode {
|
||||||
var head *FileNode = new(FileNode)
|
var head *FileNode = new(FileNode)
|
||||||
var head1 *FileNode = head
|
var head1 *FileNode = head
|
||||||
for i := range path {
|
for i := range path {
|
||||||
sepPaths := strings.Split(path[i], "/")
|
sepPaths := strings.Split(path[i]["file"], "/")
|
||||||
for j := range sepPaths {
|
for j := range sepPaths {
|
||||||
if len(head.Children) == 0 {
|
if len(head.Children) == 0 {
|
||||||
head.AddChildren(sepPaths[j])
|
head.AddChildren(sepPaths[j], path[i]["Title"])
|
||||||
head = &(head.Children[len(head.Children)-1])
|
head = &(head.Children[len(head.Children)-1])
|
||||||
} else {
|
} else {
|
||||||
var headIsChanged = false
|
var headIsChanged = false
|
||||||
@ -44,7 +61,7 @@ func GenerateDirectoryTree(path []string) *FileNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !headIsChanged {
|
if !headIsChanged {
|
||||||
head.AddChildren(sepPaths[j])
|
head.AddChildren(sepPaths[j], path[i]["Title"])
|
||||||
head = &(head.Children[len(head.Children)-1])
|
head = &(head.Children[len(head.Children)-1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
140
client/updateView.go
Normal file
140
client/updateView.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aditya-K2/fuzzy"
|
||||||
|
"github.com/aditya-K2/gomp/utils"
|
||||||
|
"github.com/aditya-K2/tview"
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetCell(text string, foreground tcell.Color, bold bool) *tview.TableCell {
|
||||||
|
return tview.NewTableCell(text).
|
||||||
|
SetAlign(tview.AlignLeft).
|
||||||
|
SetStyle(tcell.StyleDefault.
|
||||||
|
Foreground(foreground).
|
||||||
|
Background(tcell.ColorBlack).
|
||||||
|
Bold(bold))
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode) {
|
||||||
|
inputTable.Clear()
|
||||||
|
if m == nil || len(m) == 0 {
|
||||||
|
Update(f, inputTable)
|
||||||
|
} else {
|
||||||
|
for k, v := range m {
|
||||||
|
if len(f[v.Index].Children) != 0 {
|
||||||
|
inputTable.SetCell(k, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetMatchedString(
|
||||||
|
utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]"),
|
||||||
|
tcell.ColorYellow, true))
|
||||||
|
} else {
|
||||||
|
inputTable.SetCell(k, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetMatchedString(
|
||||||
|
utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]"),
|
||||||
|
tcell.ColorGreen, true))
|
||||||
|
}
|
||||||
|
if k == 15 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdatePlaylist(inputTable *tview.Table) {
|
||||||
|
_playlistAttr, _ := CONN.PlaylistInfo(-1, -1)
|
||||||
|
|
||||||
|
inputTable.Clear()
|
||||||
|
for i, j := range _playlistAttr {
|
||||||
|
_, _, w, _ := inputTable.GetInnerRect()
|
||||||
|
if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(j["file"], w/3), tcell.ColorBlue, true))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(j["Title"], w/3), tcell.ColorGreen, false))
|
||||||
|
inputTable.SetCell(i, 1,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(j["Artist"], w/3), tcell.ColorPurple, false))
|
||||||
|
inputTable.SetCell(i, 2,
|
||||||
|
GetCell(j["Album"], tcell.ColorYellow, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called
|
||||||
|
// Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main
|
||||||
|
// function this will also help in persisting the Search Results.
|
||||||
|
func UpdateSearchView(inputTable *tview.Table, c []interface{}) {
|
||||||
|
inputTable.Clear()
|
||||||
|
_, _, width, _ := inputTable.GetInnerRect()
|
||||||
|
for i, content := range c {
|
||||||
|
switch content.(type) {
|
||||||
|
case [3]string:
|
||||||
|
{
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(content.([3]string)[0], width/3), tcell.ColorGreen, false))
|
||||||
|
inputTable.SetCell(i, 1,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(content.([3]string)[1], width/3), tcell.ColorPurple, false))
|
||||||
|
inputTable.SetCell(i, 2,
|
||||||
|
GetCell(content.([3]string)[2], tcell.ColorYellow, false))
|
||||||
|
}
|
||||||
|
case [2]string:
|
||||||
|
{
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(content.([2]string)[0], width/3), tcell.ColorYellow, false))
|
||||||
|
inputTable.SetCell(i, 1,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(content.([2]string)[1], width/3), tcell.ColorPurple, false))
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
{
|
||||||
|
b := content.(string)
|
||||||
|
if !strings.HasPrefix(b, WHITE_AND_BOLD) {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(content.(string), tcell.ColorPurple, false))
|
||||||
|
} else {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(content.(string), tcell.ColorWhite, true).SetSelectable(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update(f []FileNode, inputTable *tview.Table) {
|
||||||
|
inputTable.Clear()
|
||||||
|
for i, j := range f {
|
||||||
|
if len(j.Children) == 0 {
|
||||||
|
_songAttributes, err := CONN.ListAllInfo(j.AbsolutePath)
|
||||||
|
if err == nil && _songAttributes[0]["Title"] != "" {
|
||||||
|
_, _, w, _ := inputTable.GetInnerRect()
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(_songAttributes[0]["Title"], w/3), tcell.ColorGreen, false))
|
||||||
|
|
||||||
|
inputTable.SetCell(i, 1,
|
||||||
|
GetCell(
|
||||||
|
utils.GetFormattedString(_songAttributes[0]["Artist"], w/3), tcell.ColorPurple, false))
|
||||||
|
inputTable.SetCell(i, 2,
|
||||||
|
GetCell(_songAttributes[0]["Album"], tcell.ColorYellow, false))
|
||||||
|
|
||||||
|
} else if _songAttributes[0]["Title"] == "" {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(j.Path, tcell.ColorBlue, true))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputTable.SetCell(i, 0,
|
||||||
|
GetCell(j.Path, tcell.ColorYellow, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,7 +48,8 @@ var (
|
|||||||
115: "stop",
|
115: "stop",
|
||||||
117: "updateDB",
|
117: "updateDB",
|
||||||
100: "deleteSongFromPlaylist",
|
100: "deleteSongFromPlaylist",
|
||||||
47: "FocusSearch",
|
63: "FocusSearch",
|
||||||
|
47: "FocusBuffSearch",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -143,28 +143,29 @@ togglePlayBack : [ "p", "TAB", "[" ] # using the quotes is neccessary.
|
|||||||
|
|
||||||
Following functions are provided :
|
Following functions are provided :
|
||||||
|
|
||||||
| Functions |
|
| Functions | Default Key Mapping |
|
||||||
|------------------------------------|
|
|------------------------------------|---------------------|
|
||||||
| showChildrenContent |
|
| showChildrenContent | <kbd>l</kbd> |
|
||||||
| togglePlayBack |
|
| togglePlayBack | <kbd>p</kbd> |
|
||||||
| showParentContent |
|
| showParentContent | <kbd>h</kbd> |
|
||||||
| nextSong |
|
| nextSong | <kbd>n</kbd> |
|
||||||
| clearPlaylist |
|
| clearPlaylist | <kbd>c</kbd> |
|
||||||
| previousSong |
|
| previousSong | <kbd>N</kbd> |
|
||||||
| addToPlaylist |
|
| addToPlaylist | <kbd>a</kbd> |
|
||||||
| toggleRandom |
|
| toggleRandom | <kbd>z</kbd> |
|
||||||
| toggleRepeat |
|
| toggleRepeat | <kbd>r</kbd> |
|
||||||
| decreaseVolume |
|
| decreaseVolume | <kbd>-</kbd> |
|
||||||
| increaseVolume |
|
| increaseVolume | <kbd>+</kbd> |
|
||||||
| navigateToFiles |
|
| navigateToFiles | <kbd>2</kbd> |
|
||||||
| navigateToPlaylist |
|
| navigateToPlaylist | <kbd>1</kbd> |
|
||||||
| navigateToMostPlayed |
|
| navigateToMostPlayed | <kbd>3</kbd> |
|
||||||
| navigateToSearch |
|
| navigateToSearch | <kbd>4</kbd> |
|
||||||
| quit |
|
| quit | <kbd>q</kbd> |
|
||||||
| stop |
|
| stop | <kbd>s</kbd> |
|
||||||
| updateDB |
|
| updateDB | <kbd>u</kbd> |
|
||||||
| deleteSongFromPlaylist |
|
| deleteSongFromPlaylist | <kbd>d</kbd> |
|
||||||
| FocusSearch |
|
| FocusSearch | <kbd>?</kbd> |
|
||||||
|
| FocusBuffSearch | <kbd>/</kbd> |
|
||||||
|
|
||||||
## Getting Album Art from [LastFm API](https://www.last.fm/api)
|
## Getting Album Art from [LastFm API](https://www.last.fm/api)
|
||||||
|
|
||||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/aditya-K2/gomp
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 // indirect
|
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4
|
||||||
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c
|
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c
|
||||||
github.com/bogem/id3v2 v1.2.0
|
github.com/bogem/id3v2 v1.2.0
|
||||||
github.com/fhs/gompd v1.0.1
|
github.com/fhs/gompd v1.0.1
|
||||||
|
3
go.sum
3
go.sum
@ -54,8 +54,6 @@ github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2
|
|||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 h1:GEy4yHiudZCZyhwhP/2IWkcHCSkuUv/A4vKgktkIRYE=
|
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 h1:GEy4yHiudZCZyhwhP/2IWkcHCSkuUv/A4vKgktkIRYE=
|
||||||
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4/go.mod h1:82s+GWKOo176xBYRWstoAM6Fl5jpXNuZ1syuJvRwVN8=
|
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4/go.mod h1:82s+GWKOo176xBYRWstoAM6Fl5jpXNuZ1syuJvRwVN8=
|
||||||
github.com/aditya-K2/tview v0.0.0-20211115155623-217bcbdc952c h1:HE/P4zSd5GE7wdCicacdo5m2vZk6E7BSS5NOY00gaPM=
|
|
||||||
github.com/aditya-K2/tview v0.0.0-20211115155623-217bcbdc952c/go.mod h1:nPfBlFYx4SBcLlONif45KWw2mvEbRgP/nNCkH/dMhIQ=
|
|
||||||
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c h1:UG9OxyXccanOiC83FEonB3+iLYvA3aAYgiX1N7Vurm0=
|
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c h1:UG9OxyXccanOiC83FEonB3+iLYvA3aAYgiX1N7Vurm0=
|
||||||
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c/go.mod h1:nPfBlFYx4SBcLlONif45KWw2mvEbRgP/nNCkH/dMhIQ=
|
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c/go.mod h1:nPfBlFYx4SBcLlONif45KWw2mvEbRgP/nNCkH/dMhIQ=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
@ -219,6 +217,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
88
main.go
88
main.go
@ -1,20 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aditya-K2/gomp/ui/notify"
|
"github.com/aditya-K2/gomp/cache"
|
||||||
|
"github.com/aditya-K2/gomp/client"
|
||||||
|
"github.com/aditya-K2/gomp/config"
|
||||||
"github.com/aditya-K2/gomp/render"
|
"github.com/aditya-K2/gomp/render"
|
||||||
"github.com/aditya-K2/gomp/ui"
|
"github.com/aditya-K2/gomp/ui"
|
||||||
|
"github.com/aditya-K2/gomp/ui/notify"
|
||||||
"github.com/aditya-K2/gomp/client"
|
|
||||||
"github.com/aditya-K2/gomp/utils"
|
"github.com/aditya-K2/gomp/utils"
|
||||||
|
|
||||||
"github.com/aditya-K2/fuzzy"
|
"github.com/aditya-K2/fuzzy"
|
||||||
"github.com/aditya-K2/gomp/cache"
|
|
||||||
"github.com/aditya-K2/gomp/config"
|
|
||||||
"github.com/fhs/gompd/mpd"
|
"github.com/fhs/gompd/mpd"
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -53,7 +52,7 @@ func main() {
|
|||||||
// Connecting the Notification Server to the Main UI
|
// Connecting the Notification Server to the Main UI
|
||||||
notify.ConnectUI(UI)
|
notify.ConnectUI(UI)
|
||||||
|
|
||||||
fileMap, err := CONN.GetFiles()
|
fileMap, err := CONN.ListAllInfo("/")
|
||||||
|
|
||||||
// Generating the Directory Tree for File Navigation.
|
// Generating the Directory Tree for File Navigation.
|
||||||
dirTree := client.GenerateDirectoryTree(fileMap)
|
dirTree := client.GenerateDirectoryTree(fileMap)
|
||||||
@ -81,6 +80,7 @@ func main() {
|
|||||||
|
|
||||||
// This is the Slice that is used to Display Content in the SearchView
|
// This is the Slice that is used to Display Content in the SearchView
|
||||||
var SearchContentSlice []interface{}
|
var SearchContentSlice []interface{}
|
||||||
|
var Matches fuzzy.Matches
|
||||||
|
|
||||||
// This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses
|
// This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses
|
||||||
// the Draw Function
|
// the Draw Function
|
||||||
@ -91,6 +91,8 @@ func main() {
|
|||||||
client.UpdateSearchView(UI.ExpandedView, SearchContentSlice)
|
client.UpdateSearchView(UI.ExpandedView, SearchContentSlice)
|
||||||
} else if ui.HasFocus("FileBrowser") {
|
} else if ui.HasFocus("FileBrowser") {
|
||||||
client.Update(dirTree.Children, UI.ExpandedView)
|
client.Update(dirTree.Children, UI.ExpandedView)
|
||||||
|
} else if ui.HasFocus("BuffSearchView") {
|
||||||
|
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children)
|
||||||
}
|
}
|
||||||
return UI.ExpandedView.GetInnerRect()
|
return UI.ExpandedView.GetInnerRect()
|
||||||
})
|
})
|
||||||
@ -100,20 +102,36 @@ func main() {
|
|||||||
// the respective function in this case togglePlayBack is called.
|
// the respective function in this case togglePlayBack is called.
|
||||||
var FuncMap = map[string]func(){
|
var FuncMap = map[string]func(){
|
||||||
"showChildrenContent": func() {
|
"showChildrenContent": func() {
|
||||||
r, _ := UI.ExpandedView.GetSelection()
|
|
||||||
if ui.HasFocus("FileBrowser") {
|
if ui.HasFocus("FileBrowser") {
|
||||||
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
if len(dirTree.Children[r].Children) == 0 {
|
if len(dirTree.Children[r].Children) == 0 {
|
||||||
id, _ := CONN.AddId(dirTree.Children[r].AbsolutePath, -1)
|
id, _ := CONN.AddId(dirTree.Children[r].AbsolutePath, -1)
|
||||||
CONN.PlayId(id)
|
CONN.PlayId(id)
|
||||||
} else {
|
} else {
|
||||||
client.Update(dirTree.Children[r].Children, UI.ExpandedView)
|
client.Update(dirTree.Children[r].Children, UI.ExpandedView)
|
||||||
dirTree = &dirTree.Children[r]
|
dirTree = &dirTree.Children[r]
|
||||||
|
UI.ExpandedView.Select(0, 0)
|
||||||
}
|
}
|
||||||
} else if ui.HasFocus("Playlist") {
|
} else if ui.HasFocus("Playlist") {
|
||||||
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
CONN.Play(r)
|
CONN.Play(r)
|
||||||
} else if ui.HasFocus("SearchView") {
|
} else if ui.HasFocus("SearchView") {
|
||||||
r, _ := UI.ExpandedView.GetSelection()
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
client.AddToPlaylist(SearchContentSlice[r], true)
|
client.AddToPlaylist(SearchContentSlice[r], true)
|
||||||
|
} else if ui.HasFocus("BuffSearchView") {
|
||||||
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
|
if len(dirTree.Children[r].Children) == 0 {
|
||||||
|
id, _ := CONN.AddId(dirTree.Children[Matches[r].Index].AbsolutePath, -1)
|
||||||
|
CONN.PlayId(id)
|
||||||
|
} else {
|
||||||
|
client.Update(dirTree.Children[Matches[r].Index].Children, UI.ExpandedView)
|
||||||
|
dirTree = &dirTree.Children[Matches[r].Index]
|
||||||
|
}
|
||||||
|
UI.SearchBar.SetText("")
|
||||||
|
// Resetting Matches
|
||||||
|
Matches = nil
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"togglePlayBack": func() {
|
"togglePlayBack": func() {
|
||||||
@ -144,6 +162,16 @@ func main() {
|
|||||||
} else if ui.HasFocus("SearchView") {
|
} else if ui.HasFocus("SearchView") {
|
||||||
r, _ := UI.ExpandedView.GetSelection()
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
client.AddToPlaylist(SearchContentSlice[r], false)
|
client.AddToPlaylist(SearchContentSlice[r], false)
|
||||||
|
} else if ui.HasFocus("BuffSearchView") {
|
||||||
|
r, _ := UI.ExpandedView.GetSelection()
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
|
err := CONN.Add(dirTree.Children[Matches[r].Index].AbsolutePath)
|
||||||
|
if err != nil {
|
||||||
|
Notify.Send(fmt.Sprintf("Could Not Add URI %s to the Playlist", dirTree.Children[Matches[r].Index].Path))
|
||||||
|
} else {
|
||||||
|
Notify.Send(fmt.Sprintf("URI Added %s to the Playlist", dirTree.Children[Matches[r].Index].Path))
|
||||||
|
}
|
||||||
|
ui.SetFocus("BuffSearchView")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"toggleRandom": func() {
|
"toggleRandom": func() {
|
||||||
@ -192,7 +220,13 @@ func main() {
|
|||||||
UI.Navbar.Select(3, 0)
|
UI.Navbar.Select(3, 0)
|
||||||
},
|
},
|
||||||
"quit": func() {
|
"quit": func() {
|
||||||
|
if ui.HasFocus("BuffSearchView") {
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
|
UI.SearchBar.SetText("")
|
||||||
|
Matches = nil
|
||||||
|
} else {
|
||||||
UI.App.Stop()
|
UI.App.Stop()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"stop": func() {
|
"stop": func() {
|
||||||
CONN.Stop()
|
CONN.Stop()
|
||||||
@ -214,6 +248,12 @@ func main() {
|
|||||||
"FocusSearch": func() {
|
"FocusSearch": func() {
|
||||||
UI.App.SetFocus(UI.SearchBar)
|
UI.App.SetFocus(UI.SearchBar)
|
||||||
},
|
},
|
||||||
|
"FocusBuffSearch": func() {
|
||||||
|
if ui.HasFocus("FileBrowser") || ui.HasFocus("BuffSearchView") {
|
||||||
|
ui.SetFocus("BuffSearchView")
|
||||||
|
UI.App.SetFocus(UI.SearchBar)
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generating the Key Map Based on the Function Map Here Basically the Values will be flipped
|
// Generating the Key Map Based on the Function Map Here Basically the Values will be flipped
|
||||||
@ -222,6 +262,9 @@ func main() {
|
|||||||
config.GenerateKeyMap(FuncMap)
|
config.GenerateKeyMap(FuncMap)
|
||||||
|
|
||||||
UI.SearchBar.SetAutocompleteFunc(func(c string) []string {
|
UI.SearchBar.SetAutocompleteFunc(func(c string) []string {
|
||||||
|
if ui.HasFocus("BuffSearchView") {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
if c != "" && c != " " && c != " " {
|
if c != "" && c != " " && c != " " {
|
||||||
_, _, w, _ := UI.SearchBar.GetRect()
|
_, _, w, _ := UI.SearchBar.GetRect()
|
||||||
matches := fuzzy.Find(c, ArtistTreeContent)
|
matches := fuzzy.Find(c, ArtistTreeContent)
|
||||||
@ -236,6 +279,7 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
return make([]string, 0)
|
return make([]string, 0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Input Handler
|
// Input Handler
|
||||||
@ -251,6 +295,9 @@ func main() {
|
|||||||
UI.SearchBar.SetDoneFunc(func(e tcell.Key) {
|
UI.SearchBar.SetDoneFunc(func(e tcell.Key) {
|
||||||
if e == tcell.KeyEnter {
|
if e == tcell.KeyEnter {
|
||||||
UI.ExpandedView.Select(0, 0)
|
UI.ExpandedView.Select(0, 0)
|
||||||
|
if ui.HasFocus("BuffSearchView") {
|
||||||
|
UI.App.SetFocus(UI.ExpandedView)
|
||||||
|
} else {
|
||||||
ui.SetFocus("SearchView")
|
ui.SetFocus("SearchView")
|
||||||
SearchContentSlice = nil
|
SearchContentSlice = nil
|
||||||
SearchContentSlice, err = client.GenerateContentSlice(UI.SearchBar.GetText())
|
SearchContentSlice, err = client.GenerateContentSlice(UI.SearchBar.GetText())
|
||||||
@ -262,12 +309,37 @@ func main() {
|
|||||||
UI.Navbar.Select(3, 0)
|
UI.Navbar.Select(3, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if e == tcell.KeyEscape {
|
if e == tcell.KeyEscape {
|
||||||
|
if ui.HasFocus("SearchView") {
|
||||||
ui.FocusMap["SearchView"] = false
|
ui.FocusMap["SearchView"] = false
|
||||||
|
} else if ui.HasFocus("BuffSearchView") {
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
|
Matches = nil
|
||||||
|
}
|
||||||
|
UI.SearchBar.SetText("")
|
||||||
UI.App.SetFocus(UI.ExpandedView)
|
UI.App.SetFocus(UI.ExpandedView)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
UI.ExpandedView.SetDoneFunc(func(e tcell.Key) {
|
||||||
|
if e == tcell.KeyEscape {
|
||||||
|
if ui.HasFocus("BuffSearchView") {
|
||||||
|
ui.SetFocus("FileBrowser")
|
||||||
|
UI.SearchBar.SetText("")
|
||||||
|
Matches = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
UI.SearchBar.SetChangedFunc(func(text string) {
|
||||||
|
if ui.HasFocus("BuffSearchView") {
|
||||||
|
var f client.FileNodes = dirTree.Children
|
||||||
|
Matches = fuzzy.FindFrom(text, f)
|
||||||
|
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
UI.App.Draw()
|
UI.App.Draw()
|
||||||
|
@ -36,10 +36,10 @@ func NewApplication() *Application {
|
|||||||
imagePreviewer.SetBackgroundColor(tcell.ColorDefault)
|
imagePreviewer.SetBackgroundColor(tcell.ColorDefault)
|
||||||
|
|
||||||
searchBar.SetTitle("Search").SetTitleAlign(tview.AlignLeft)
|
searchBar.SetTitle("Search").SetTitleAlign(tview.AlignLeft)
|
||||||
searchBar.SetAutocompleteBackgroundColor(tcell.GetColor("#15191a"))
|
searchBar.SetAutocompleteBackgroundColor(tcell.ColorBlack)
|
||||||
searchBar.SetAutocompleteSelectBackgroundColor(tcell.GetColor("#e5e5e5"))
|
searchBar.SetAutocompleteSelectBackgroundColor(tcell.ColorWhite)
|
||||||
searchBar.SetAutocompleteMainTextColor(tcell.GetColor("#7f7f7f"))
|
searchBar.SetAutocompleteMainTextColor(tcell.ColorDarkGray)
|
||||||
searchBar.SetAutocompleteSelectedTextColor(tcell.GetColor("#111111"))
|
searchBar.SetAutocompleteSelectedTextColor(tcell.ColorBlack)
|
||||||
Navbar.SetBorder(true)
|
Navbar.SetBorder(true)
|
||||||
Navbar.SetSelectable(true, false)
|
Navbar.SetSelectable(true, false)
|
||||||
Navbar.SetCell(0, 0, tview.NewTableCell("PlayList"))
|
Navbar.SetCell(0, 0, tview.NewTableCell("PlayList"))
|
||||||
|
@ -10,6 +10,7 @@ func GenerateFocusMap() {
|
|||||||
FocusMap["Playlist"] = true
|
FocusMap["Playlist"] = true
|
||||||
FocusMap["FileBrowser"] = false
|
FocusMap["FileBrowser"] = false
|
||||||
FocusMap["SearchView"] = false
|
FocusMap["SearchView"] = false
|
||||||
|
FocusMap["BuffSearchView"] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func HasFocus(s string) bool {
|
func HasFocus(s string) bool {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package notify
|
package notify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/aditya-K2/gomp/ui"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aditya-K2/gomp/ui"
|
||||||
|
|
||||||
"github.com/aditya-K2/gomp/utils"
|
"github.com/aditya-K2/gomp/utils"
|
||||||
|
|
||||||
"github.com/aditya-K2/tview"
|
"github.com/aditya-K2/tview"
|
||||||
@ -43,12 +44,12 @@ func (self *Notification) Draw(screen tcell.Screen) {
|
|||||||
TEXTPOSITION int = 2
|
TEXTPOSITION int = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
self.Box.SetBackgroundColor(tcell.GetColor("#15191a"))
|
self.Box.SetBackgroundColor(tcell.ColorBlack)
|
||||||
self.SetRect(COL-(TEXTLENGTH+7), 1, TEXTLENGTH+4, HEIGHT)
|
self.SetRect(COL-(TEXTLENGTH+7), 1, TEXTLENGTH+4, HEIGHT)
|
||||||
self.DrawForSubclass(screen, self.Box)
|
self.DrawForSubclass(screen, self.Box)
|
||||||
tview.Print(screen, self.Text,
|
tview.Print(screen, self.Text,
|
||||||
COL-(TEXTLENGTH+5), TEXTPOSITION, TEXTLENGTH,
|
COL-(TEXTLENGTH+5), TEXTPOSITION, TEXTLENGTH,
|
||||||
tview.AlignCenter, tcell.GetColor("#ffffff"))
|
tview.AlignCenter, tcell.ColorWhite)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notification Server : Not an actual Server*/
|
/* Notification Server : Not an actual Server*/
|
||||||
|
@ -59,7 +59,7 @@ func InsertAt(inputString, stringTobeInserted string, index int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetText(width, percentage float64, eta string) string {
|
func GetText(width, percentage float64, eta string) string {
|
||||||
q := "[#000000:#ffffff:b]"
|
q := "[black:white:b]"
|
||||||
var a string
|
var a string
|
||||||
a += strings.Repeat(" ", int(width)-len(eta))
|
a += strings.Repeat(" ", int(width)-len(eta))
|
||||||
a = InsertAt(a, eta, int(width/2)-10)
|
a = InsertAt(a, eta, int(width/2)-10)
|
||||||
@ -136,3 +136,48 @@ func CheckDirectoryFmt(path string) string {
|
|||||||
return path + "/"
|
return path + "/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMatchedString(a []int, s, color string) string {
|
||||||
|
// The Matches are sorted so we just have to traverse the Matches and if the two adjacent matches are not consecutive
|
||||||
|
// then we append the color string at the start + offset and the nulcol ( reset ) at end + offset + 1 and then reset
|
||||||
|
// start and end to a[k+1] for e.g if matches := []int{1, 2, 4, 5, 6, 9} then the start will be 1 and end will be 1
|
||||||
|
// now until we reach `4` the value of end will change to `2` that means when we reach `4` the s string will be
|
||||||
|
// `O[yellow:-:-]ut[-:-:-]putString` after that until we reach the end will be changed and finally become `6` and the
|
||||||
|
// s string will be `O[yellow:-:-]ut[-:-:-]p[yellow:-:-]utS[-:-:-]tring`
|
||||||
|
// Please note that after around 45 simulatenously highlighted characters tview stops highlighting and the color
|
||||||
|
// sequences are rendered hope no one has that big of search query.
|
||||||
|
start := a[0]
|
||||||
|
end := a[0]
|
||||||
|
offset := 0
|
||||||
|
nulcol := "[-:-:-]"
|
||||||
|
for k := range a {
|
||||||
|
if k < len(a)-1 && a[k+1]-a[k] == 1 {
|
||||||
|
end = a[k+1]
|
||||||
|
} else if k < len(a)-1 {
|
||||||
|
s = InsertAt(s, color, start+offset)
|
||||||
|
offset += len(color)
|
||||||
|
s = InsertAt(s, nulcol, end+offset+1)
|
||||||
|
offset += len(nulcol)
|
||||||
|
start = a[k+1]
|
||||||
|
end = a[k+1]
|
||||||
|
} else if k == len(a)-1 {
|
||||||
|
s = InsertAt(s, color, start+offset)
|
||||||
|
offset += len(color)
|
||||||
|
s = InsertAt(s, nulcol, end+offset+1)
|
||||||
|
offset += len(nulcol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unique(intSlice []int) []int {
|
||||||
|
keys := make(map[int]bool)
|
||||||
|
list := []int{}
|
||||||
|
for _, entry := range intSlice {
|
||||||
|
if _, exists := keys[entry]; !exists {
|
||||||
|
keys[entry] = true
|
||||||
|
list = append(list, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user