mirror of
https://github.com/issadarkthing/gomu.git
synced 2025-05-04 22:17:48 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1362c9925b
@ -101,8 +101,8 @@ Each panel has it's own additional keybinding. To view the available keybinding
|
||||
|
||||
### Scripting
|
||||
|
||||
Gomu uses [anko](github.com/mattn/anko) as its scripting language. You can read
|
||||
more about scripting at our [wiki](github.com/issadarkthing/gomu/wiki)
|
||||
Gomu uses [anko](https://github.com/mattn/anko) as its scripting language. You can read
|
||||
more about scripting at our [wiki](https://github.com/issadarkthing/gomu/wiki)
|
||||
|
||||
``` go
|
||||
|
||||
|
@ -17,7 +17,7 @@ type Anko struct {
|
||||
env *env.Env
|
||||
}
|
||||
|
||||
func NewAnko() Anko {
|
||||
func NewAnko() *Anko {
|
||||
|
||||
env := core.Import(env.NewEnv())
|
||||
importToX(env)
|
||||
@ -45,7 +45,7 @@ func NewAnko() Anko {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return Anko{env}
|
||||
return &Anko{env}
|
||||
}
|
||||
|
||||
// Define defines new symbol and value to the Anko env.
|
||||
|
97
command.go
97
command.go
@ -1,10 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/ztrue/tracerr"
|
||||
)
|
||||
@ -66,98 +62,7 @@ func (c Command) defineCommands() {
|
||||
})
|
||||
|
||||
c.define("youtube_search", func() {
|
||||
|
||||
popupId := "youtube-search-input-popup"
|
||||
|
||||
input := newInputPopup(popupId, " Youtube Search ", "search: ", "")
|
||||
|
||||
// quick hack to change the autocomplete text color
|
||||
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack
|
||||
input.SetAutocompleteFunc(func(currentText string) (entries []string) {
|
||||
|
||||
if currentText == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
suggestions, err := getSuggestions(currentText)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
}
|
||||
|
||||
return suggestions
|
||||
})
|
||||
|
||||
input.SetDoneFunc(func(key tcell.Key) {
|
||||
|
||||
switch key {
|
||||
case tcell.KeyEnter:
|
||||
search := input.GetText()
|
||||
defaultTimedPopup(" Youtube Search ", "Searching for "+search)
|
||||
gomu.pages.RemovePage(popupId)
|
||||
gomu.popups.pop()
|
||||
|
||||
go func() {
|
||||
|
||||
results, err := getSearchResult(search)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
defaultTimedPopup(" Error ", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
titles := []string{}
|
||||
urls := make(map[string]string)
|
||||
|
||||
for _, result := range results {
|
||||
duration, err := time.ParseDuration(fmt.Sprintf("%ds", result.LengthSeconds))
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
durationText := fmt.Sprintf("[ %s ] ", fmtDuration(duration))
|
||||
title := durationText + result.Title
|
||||
|
||||
urls[title] = `https://www.youtube.com/watch?v=` + result.VideoId
|
||||
|
||||
titles = append(titles, title)
|
||||
}
|
||||
|
||||
searchPopup("Youtube Videos", titles, func(title string) {
|
||||
|
||||
audioFile := gomu.playlist.getCurrentFile()
|
||||
|
||||
var dir *tview.TreeNode
|
||||
|
||||
if audioFile.isAudioFile {
|
||||
dir = audioFile.parent
|
||||
} else {
|
||||
dir = audioFile.node
|
||||
}
|
||||
|
||||
go func() {
|
||||
url := urls[title]
|
||||
if err := ytdl(url, dir); err != nil {
|
||||
logError(err)
|
||||
}
|
||||
gomu.playlist.refresh()
|
||||
}()
|
||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||
})
|
||||
|
||||
gomu.app.Draw()
|
||||
}()
|
||||
|
||||
case tcell.KeyEscape:
|
||||
gomu.pages.RemovePage(popupId)
|
||||
gomu.popups.pop()
|
||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||
|
||||
default:
|
||||
input.Autocomplete()
|
||||
}
|
||||
|
||||
})
|
||||
ytSearchPopup()
|
||||
})
|
||||
|
||||
c.define("download_audio", func() {
|
||||
|
25
command_test.go
Normal file
25
command_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
func TestGetFn(t *testing.T) {
|
||||
|
||||
c := newCommand()
|
||||
|
||||
c.define("sample", func() {})
|
||||
|
||||
f, err := c.getFn("sample")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
assert.NotNil(t, f)
|
||||
|
||||
f, err = c.getFn("x")
|
||||
assert.Error(t, err)
|
||||
}
|
7
gomu.go
7
gomu.go
@ -1,9 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/issadarkthing/gomu/anko"
|
||||
"github.com/issadarkthing/gomu/hook"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/ztrue/tracerr"
|
||||
"github.com/issadarkthing/gomu/anko"
|
||||
)
|
||||
|
||||
var VERSION = "N/A"
|
||||
@ -24,7 +25,8 @@ type Gomu struct {
|
||||
prevPanel Panel
|
||||
panels []Panel
|
||||
args Args
|
||||
anko anko.Anko
|
||||
anko *anko.Anko
|
||||
hook *hook.EventHook
|
||||
}
|
||||
|
||||
// Creates new instance of gomu with default values
|
||||
@ -33,6 +35,7 @@ func newGomu() *Gomu {
|
||||
gomu := &Gomu{
|
||||
command: newCommand(),
|
||||
anko: anko.NewAnko(),
|
||||
hook: hook.NewEventHook(),
|
||||
}
|
||||
|
||||
return gomu
|
||||
|
35
hook/hook.go
Normal file
35
hook/hook.go
Normal file
@ -0,0 +1,35 @@
|
||||
package hook
|
||||
|
||||
type EventHook struct {
|
||||
events map[string][]func()
|
||||
}
|
||||
|
||||
// NewNewEventHook returns new instance of EventHook
|
||||
func NewEventHook() *EventHook {
|
||||
return &EventHook{make(map[string][]func())}
|
||||
}
|
||||
|
||||
// AddHook accepts a function which will be executed when the event is emitted.
|
||||
func (e *EventHook) AddHook(eventName string, handler func()) {
|
||||
|
||||
hooks, ok := e.events[eventName]
|
||||
if !ok {
|
||||
e.events[eventName] = []func(){handler}
|
||||
return
|
||||
}
|
||||
|
||||
e.events[eventName] = append(hooks, handler)
|
||||
}
|
||||
|
||||
// RunHooks executes all hooks installed for an event.
|
||||
func (e *EventHook) RunHooks(eventName string) {
|
||||
|
||||
hooks, ok := e.events[eventName]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, hook := range hooks {
|
||||
hook()
|
||||
}
|
||||
}
|
57
hook/hook_test.go
Normal file
57
hook/hook_test.go
Normal file
@ -0,0 +1,57 @@
|
||||
package hook
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddHook(t *testing.T) {
|
||||
|
||||
h := NewEventHook()
|
||||
|
||||
h.AddHook("a", nil)
|
||||
h.AddHook("a", nil)
|
||||
h.AddHook("a", nil)
|
||||
h.AddHook("a", nil)
|
||||
|
||||
assert.Equal(t, 1, len(h.events), "should only contain 1 event")
|
||||
|
||||
hooks := h.events["a"]
|
||||
assert.Equal(t, 4, len(hooks), "should contain 4 hooks")
|
||||
|
||||
h.AddHook("b", nil)
|
||||
h.AddHook("c", nil)
|
||||
|
||||
assert.Equal(t, 3, len(h.events), "should contain 3 events")
|
||||
}
|
||||
|
||||
func TestRunHooks(t *testing.T) {
|
||||
|
||||
h := NewEventHook()
|
||||
x := 0
|
||||
|
||||
for i := 0; i < 100; i ++ {
|
||||
h.AddHook("sample", func() {
|
||||
x++
|
||||
})
|
||||
}
|
||||
|
||||
h.AddHook("noop", func() {
|
||||
x++
|
||||
})
|
||||
|
||||
h.AddHook("noop", func() {
|
||||
x++
|
||||
})
|
||||
|
||||
assert.Equal(t, x, 0, "should not execute any hook")
|
||||
|
||||
h.RunHooks("x")
|
||||
|
||||
assert.Equal(t, x, 0, "should not execute any hook")
|
||||
|
||||
h.RunHooks("sample")
|
||||
|
||||
assert.Equal(t, x, 100, "should only execute event 'sample'")
|
||||
}
|
10
player.go
10
player.go
@ -121,7 +121,10 @@ func (p *Player) run(currSong *AudioFile) error {
|
||||
// sets the volume of previous player
|
||||
volume.Volume += p.volume
|
||||
p._volume = volume
|
||||
|
||||
// starts playing the audio
|
||||
speaker.Play(p._volume)
|
||||
gomu.hook.RunHooks("new_song")
|
||||
|
||||
p.isRunning = true
|
||||
|
||||
@ -157,6 +160,7 @@ next:
|
||||
// when there are no songs to be played, set currentSong as nil
|
||||
p.currentSong = nil
|
||||
gomu.playingBar.setDefault()
|
||||
gomu.app.Draw()
|
||||
break next
|
||||
}
|
||||
|
||||
@ -190,6 +194,7 @@ next:
|
||||
}
|
||||
|
||||
func (p *Player) pause() {
|
||||
gomu.hook.RunHooks("pause")
|
||||
speaker.Lock()
|
||||
p.ctrl.Paused = true
|
||||
p.isRunning = false
|
||||
@ -197,6 +202,7 @@ func (p *Player) pause() {
|
||||
}
|
||||
|
||||
func (p *Player) play() {
|
||||
gomu.hook.RunHooks("play")
|
||||
speaker.Lock()
|
||||
p.ctrl.Paused = false
|
||||
p.isRunning = true
|
||||
@ -235,7 +241,9 @@ func (p *Player) togglePause() {
|
||||
// skips current song
|
||||
func (p *Player) skip() {
|
||||
|
||||
if gomu.queue.GetItemCount() < 1 {
|
||||
gomu.hook.RunHooks("skip")
|
||||
|
||||
if p.currentSong == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -38,14 +38,6 @@ func newPlayingBar() *PlayingBar {
|
||||
progress: make(chan int),
|
||||
}
|
||||
|
||||
textView.SetChangedFunc(func() {
|
||||
gomu.app.Draw()
|
||||
|
||||
if !gomu.player.isRunning {
|
||||
p.setDefault()
|
||||
}
|
||||
})
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@ -84,6 +76,7 @@ func (p *PlayingBar) run() error {
|
||||
progressBar,
|
||||
fmtDuration(end),
|
||||
))
|
||||
gomu.app.Draw()
|
||||
|
||||
}
|
||||
|
||||
|
139
popup.go
139
popup.go
@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
@ -53,6 +54,8 @@ func (s *Stack) pop() tview.Primitive {
|
||||
}
|
||||
|
||||
last := s.popups[len(s.popups)-1]
|
||||
s.popups[len(s.popups)-1] = nil // avoid memory leak
|
||||
|
||||
res := s.popups[:len(s.popups)-1]
|
||||
s.popups = res
|
||||
|
||||
@ -611,16 +614,20 @@ func replPopup() {
|
||||
|
||||
switch event.Key() {
|
||||
case tcell.KeyUp:
|
||||
input.SetText(history[upCount])
|
||||
|
||||
if upCount < len(history)-1 {
|
||||
if upCount < len(history) {
|
||||
input.SetText(history[upCount])
|
||||
upCount++
|
||||
}
|
||||
|
||||
case tcell.KeyDown:
|
||||
|
||||
if upCount > 0 {
|
||||
upCount--
|
||||
if upCount == len(history) {
|
||||
upCount -= 2
|
||||
} else {
|
||||
upCount -= 1
|
||||
}
|
||||
input.SetText(history[upCount])
|
||||
} else if upCount == 0 {
|
||||
input.SetText("")
|
||||
@ -642,15 +649,20 @@ func replPopup() {
|
||||
|
||||
input.SetText("")
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, err)
|
||||
}
|
||||
}()
|
||||
|
||||
res, err := gomu.anko.Execute(text)
|
||||
if err != nil {
|
||||
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if res != nil {
|
||||
} else {
|
||||
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, res)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return event
|
||||
@ -671,6 +683,121 @@ func replPopup() {
|
||||
gomu.popups.push(flex)
|
||||
}
|
||||
|
||||
func ytSearchPopup() {
|
||||
|
||||
popupId := "youtube-search-input-popup"
|
||||
|
||||
input := newInputPopup(popupId, " Youtube Search ", "search: ", "")
|
||||
|
||||
var mutex sync.Mutex
|
||||
prefixMap := make(map[string][]string)
|
||||
|
||||
// quick hack to change the autocomplete text color
|
||||
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack
|
||||
input.SetAutocompleteFunc(func(currentText string) []string {
|
||||
|
||||
// Ignore empty text.
|
||||
prefix := strings.TrimSpace(strings.ToLower(currentText))
|
||||
if prefix == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
entries, ok := prefixMap[prefix]
|
||||
if ok {
|
||||
return entries
|
||||
}
|
||||
|
||||
go func() {
|
||||
suggestions, err := getSuggestions(currentText)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
mutex.Lock()
|
||||
prefixMap[prefix] = suggestions
|
||||
mutex.Unlock()
|
||||
|
||||
input.Autocomplete()
|
||||
gomu.app.Draw()
|
||||
}()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
input.SetDoneFunc(func(key tcell.Key) {
|
||||
|
||||
switch key {
|
||||
case tcell.KeyEnter:
|
||||
search := input.GetText()
|
||||
defaultTimedPopup(" Youtube Search ", "Searching for "+search)
|
||||
gomu.pages.RemovePage(popupId)
|
||||
gomu.popups.pop()
|
||||
|
||||
go func() {
|
||||
|
||||
results, err := getSearchResult(search)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
defaultTimedPopup(" Error ", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
titles := []string{}
|
||||
urls := make(map[string]string)
|
||||
|
||||
for _, result := range results {
|
||||
duration, err := time.ParseDuration(fmt.Sprintf("%ds", result.LengthSeconds))
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
|
||||
durationText := fmt.Sprintf("[ %s ] ", fmtDuration(duration))
|
||||
title := durationText + result.Title
|
||||
|
||||
urls[title] = `https://www.youtube.com/watch?v=` + result.VideoId
|
||||
|
||||
titles = append(titles, title)
|
||||
}
|
||||
|
||||
searchPopup("Youtube Videos", titles, func(title string) {
|
||||
|
||||
audioFile := gomu.playlist.getCurrentFile()
|
||||
|
||||
var dir *tview.TreeNode
|
||||
|
||||
if audioFile.isAudioFile {
|
||||
dir = audioFile.parent
|
||||
} else {
|
||||
dir = audioFile.node
|
||||
}
|
||||
|
||||
go func() {
|
||||
url := urls[title]
|
||||
if err := ytdl(url, dir); err != nil {
|
||||
logError(err)
|
||||
}
|
||||
gomu.playlist.refresh()
|
||||
}()
|
||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||
})
|
||||
|
||||
gomu.app.Draw()
|
||||
}()
|
||||
|
||||
case tcell.KeyEscape:
|
||||
gomu.pages.RemovePage(popupId)
|
||||
gomu.popups.pop()
|
||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func tagPopup(node *AudioFile) bool {
|
||||
var tag *id3v2.Tag
|
||||
var err error
|
||||
|
85
start.go
85
start.go
@ -13,6 +13,8 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/issadarkthing/gomu/anko"
|
||||
"github.com/issadarkthing/gomu/hook"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/ztrue/tracerr"
|
||||
)
|
||||
@ -62,9 +64,33 @@ func defineBuiltins() {
|
||||
gomu.anko.Define("shell", shell)
|
||||
}
|
||||
|
||||
// execInit executes helper modules and default config that should only be
|
||||
func setupHooks(hook *hook.EventHook, anko *anko.Anko) {
|
||||
|
||||
events := []string{
|
||||
"enter",
|
||||
"new_song",
|
||||
"skip",
|
||||
"play",
|
||||
"pause",
|
||||
"exit",
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
name := event
|
||||
hook.AddHook(name, func() {
|
||||
src := fmt.Sprintf(`Event.run_hooks("%s")`, name)
|
||||
_, err := anko.Execute(src)
|
||||
if err != nil {
|
||||
err = tracerr.Errorf("error execute hook: %w", err)
|
||||
logError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// loadModules executes helper modules and default config that should only be
|
||||
// executed once
|
||||
func execInit() error {
|
||||
func loadModules(env *anko.Anko) error {
|
||||
|
||||
const listModule = `
|
||||
module List {
|
||||
@ -94,6 +120,35 @@ module List {
|
||||
return acc
|
||||
}
|
||||
}
|
||||
`
|
||||
const eventModule = `
|
||||
module Event {
|
||||
events = {}
|
||||
|
||||
func add_hook(name, f) {
|
||||
hooks = events[name]
|
||||
|
||||
if hooks == nil {
|
||||
events[name] = [f]
|
||||
return
|
||||
}
|
||||
|
||||
hooks += f
|
||||
events[name] = hooks
|
||||
}
|
||||
|
||||
func run_hooks(name) {
|
||||
hooks = events[name]
|
||||
|
||||
if hooks == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for hook in hooks {
|
||||
hook()
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const keybindModule = `
|
||||
@ -115,8 +170,7 @@ module Keybinds {
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
_, err := gomu.anko.Execute(listModule + keybindModule)
|
||||
_, err := env.Execute(eventModule + listModule + keybindModule)
|
||||
if err != nil {
|
||||
return tracerr.Wrap(err)
|
||||
}
|
||||
@ -231,7 +285,8 @@ func start(application *tview.Application, args Args) {
|
||||
gomu = newGomu()
|
||||
gomu.command.defineCommands()
|
||||
defineBuiltins()
|
||||
err := execInit()
|
||||
|
||||
err := loadModules(gomu.anko)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
@ -241,6 +296,9 @@ func start(application *tview.Application, args Args) {
|
||||
die(err)
|
||||
}
|
||||
|
||||
setupHooks(gomu.hook, gomu.anko)
|
||||
|
||||
gomu.hook.RunHooks("enter")
|
||||
gomu.args = args
|
||||
gomu.colors = newColor()
|
||||
|
||||
@ -357,15 +415,26 @@ func start(application *tview.Application, args Args) {
|
||||
})
|
||||
|
||||
// fix transparent background issue
|
||||
application.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
|
||||
gomu.app.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
|
||||
screen.Clear()
|
||||
return false
|
||||
})
|
||||
|
||||
init := false
|
||||
gomu.app.SetAfterDrawFunc(func(_ tcell.Screen) {
|
||||
if !init && !gomu.player.isRunning {
|
||||
gomu.playingBar.setDefault()
|
||||
init = true
|
||||
}
|
||||
})
|
||||
|
||||
go populateAudioLength(gomu.playlist.GetRoot())
|
||||
gomu.app.SetRoot(gomu.pages, true).SetFocus(gomu.playlist)
|
||||
|
||||
// main loop
|
||||
if err := application.SetRoot(gomu.pages, true).SetFocus(gomu.playlist).Run(); err != nil {
|
||||
logError(err)
|
||||
if err := gomu.app.Run(); err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
gomu.hook.RunHooks("exit")
|
||||
}
|
||||
|
47
start_test.go
Normal file
47
start_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/issadarkthing/gomu/anko"
|
||||
"github.com/issadarkthing/gomu/hook"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
func TestSetupHooks(t *testing.T) {
|
||||
|
||||
gomu := newGomu()
|
||||
gomu.anko = anko.NewAnko()
|
||||
gomu.hook = hook.NewEventHook()
|
||||
|
||||
err := loadModules(gomu.anko)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
setupHooks(gomu.hook, gomu.anko)
|
||||
|
||||
const src = `
|
||||
i = 0
|
||||
|
||||
Event.add_hook("skip", func() {
|
||||
i++
|
||||
})
|
||||
`
|
||||
|
||||
_, err = gomu.anko.Execute(src)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
gomu.hook.RunHooks("enter")
|
||||
|
||||
for i := 0; i < 12; i++ {
|
||||
gomu.hook.RunHooks("skip")
|
||||
}
|
||||
|
||||
got := gomu.anko.GetInt("i")
|
||||
|
||||
assert.Equal(t, 12, got)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user