Browse Source

open urls in different programs

pull/41/head
Rasmus Lindroth 5 years ago
parent
commit
d643ecc72b
  1. 2
      authoverlay.go
  2. 37
      config.example.ini
  3. 146
      config.go
  4. 2
      go.mod
  5. 4
      go.sum
  6. 60
      linkoverlay.go
  7. 23
      util.go

2
authoverlay.go

@ -66,7 +66,7 @@ func (a *AuthOverlay) GotInput() {
return
}
a.account = acc
openURL(a.app.Config.Media, acc.AuthURI)
openURL(a.app.Config.Media, a.app.Config.OpenPattern, acc.AuthURI)
a.Input.SetText("")
a.authStep = authCodeStep
a.Draw()

37
config.example.ini

@ -85,6 +85,43 @@ audio-single=true
# default=xdg-open
link-viewer=xdg-open
[open-custom]
# This sections allows you to set up to five custom programs to upen URLs with.
# If the url points to an image, you can set c1-name to img and c1-use to imv.
# The name will show up in the UI, so keep it short so all five fits.
#
# c1-name=img
# c1-use=imv
#
# c2-name=
# c2-use=
#
# c3-name=
# c3-use=
#
# c4-name=
# c4-use=
#
# c5-name=
# c5-use=
[open-pattern]
# Here you can set your own glob patterns for opening matching URLs in the
# program you want them to open up in.
# You could for example open Youtube videos in your video player instead of
# your default browser.
#
# You must name the keys foo-pattern and foo-use, where use is the program
# that will open up the URL. To see the syntax for glob pattern you can follow
# this URL https://github.com/gobwas/glob#syntax
#
# Example for youtube.com and youtu.be to open up in mpv instead of the browser
#
# y1-pattern=*youtube.com/watch*
# y1-use=mpv
# y2-pattern=*youtu.be/*
# y2-use=mpv
[style]
# All styles can be represented in their HEX value like #ffffff or
# with their name, so in this case white.

146
config.go

@ -1,18 +1,22 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/gdamore/tcell/v2"
"github.com/gobwas/glob"
"github.com/kyoh86/xdg"
"gopkg.in/ini.v1"
)
type Config struct {
General GeneralConfig
Style StyleConfig
Media MediaConfig
General GeneralConfig
Style StyleConfig
Media MediaConfig
OpenPattern OpenPatternConfig
OpenCustom OpenCustomConfig
}
type GeneralConfig struct {
@ -63,6 +67,28 @@ type MediaConfig struct {
LinkArgs []string
}
type Pattern struct {
Pattern string
Open string
Compiled glob.Glob
Program string
Args []string
}
type OpenPatternConfig struct {
Patterns []Pattern
}
type OpenCustom struct {
Index int
Name string
Program string
Args []string
}
type OpenCustomConfig struct {
OpenCustoms []OpenCustom
}
func parseColor(input string, def string, xrdb map[string]string) tcell.Color {
if input == "" {
return tcell.GetColor(def)
@ -239,6 +265,80 @@ func parseMedia(cfg *ini.File) MediaConfig {
return media
}
func ParseOpenPattern(cfg *ini.File) OpenPatternConfig {
om := OpenPatternConfig{}
keys := cfg.Section("open-pattern").KeyStrings()
pairs := make(map[string]Pattern)
for _, s := range keys {
parts := strings.Split(s, "-")
if len(parts) < 2 {
panic(fmt.Sprintf("Invalid key %s in config. Must end in -pattern or -use", s))
}
last := parts[len(parts)-1]
if last != "pattern" && last != "use" {
panic(fmt.Sprintf("Invalid key %s in config. Must end in -pattern or -use", s))
}
name := strings.Join(parts[:len(parts)-1], "-")
if _, ok := pairs[name]; !ok {
pairs[name] = Pattern{}
}
if last == "pattern" {
tmp := pairs[name]
tmp.Pattern = cfg.Section("open-pattern").Key(s).MustString("")
pairs[name] = tmp
}
if last == "use" {
tmp := pairs[name]
tmp.Open = cfg.Section("open-pattern").Key(s).MustString("")
pairs[name] = tmp
}
}
for key := range pairs {
if pairs[key].Pattern == "" {
panic(fmt.Sprintf("Invalid value for key %s in config. Can't be empty", key+"-pattern"))
}
if pairs[key].Open == "" {
panic(fmt.Sprintf("Invalid value for key %s in config. Can't be empty", key+"-use"))
}
compiled, err := glob.Compile(pairs[key].Pattern)
if err != nil {
panic(fmt.Sprintf("Couldn't compile pattern for key %s in config. Error: %v", key+"-pattern", err))
}
tmp := pairs[key]
tmp.Compiled = compiled
comp := strings.Fields(tmp.Open)
tmp.Program = comp[0]
tmp.Args = comp[1:]
om.Patterns = append(om.Patterns, tmp)
}
return om
}
func ParseCustom(cfg *ini.File) OpenCustomConfig {
oc := OpenCustomConfig{}
for i := 1; i < 6; i++ {
name := cfg.Section("open-custom").Key(fmt.Sprintf("c%d-name", i)).MustString("")
use := cfg.Section("open-custom").Key(fmt.Sprintf("c%d-use", i)).MustString("")
if use == "" {
continue
}
comp := strings.Fields(use)
c := OpenCustom{}
c.Index = i
c.Name = name
c.Program = comp[0]
c.Args = comp[1:]
oc.OpenCustoms = append(oc.OpenCustoms, c)
}
return oc
}
func ParseConfig(filepath string) (Config, error) {
cfg, err := ini.LoadSources(ini.LoadOptions{
SpaceBeforeInlineComment: true,
@ -250,6 +350,9 @@ func ParseConfig(filepath string) (Config, error) {
conf.General = parseGeneral(cfg)
conf.Media = parseMedia(cfg)
conf.Style = parseStyle(cfg)
conf.OpenPattern = ParseOpenPattern(cfg)
conf.OpenCustom = ParseCustom(cfg)
return conf, nil
}
@ -358,6 +461,43 @@ audio-single=true
# default=xdg-open
link-viewer=xdg-open
[open-custom]
# This sections allows you to set up to five custom programs to upen URLs with.
# If the url points to an image, you can set c1-name to img and c1-use to imv.
# The name will show up in the UI, so keep it short so all five fits.
#
# c1-name=img
# c1-use=imv
#
# c2-name=
# c2-use=
#
# c3-name=
# c3-use=
#
# c4-name=
# c4-use=
#
# c5-name=
# c5-use=
[open-pattern]
# Here you can set your own glob patterns for opening matching URLs in the
# program you want them to open up in.
# You could for example open Youtube videos in your video player instead of
# your default browser.
#
# You must name the keys foo-pattern and foo-use, where use is the program
# that will open up the URL. To see the syntax for glob pattern you can follow
# this URL https://github.com/gobwas/glob#syntax
#
# Example for youtube.com and youtu.be to open up in mpv instead of the browser
#
# y1-pattern=*youtube.com/watch*
# y1-use=mpv
# y2-pattern=*youtu.be/*
# y2-use=mpv
[style]
# All styles can be represented in their HEX value like #ffffff or
# with their name, so in this case white.

2
go.mod

@ -3,7 +3,9 @@ module github.com/RasmusLindroth/tut
go 1.14
require (
github.com/atotto/clipboard v0.1.4
github.com/gdamore/tcell/v2 v2.3.11
github.com/gobwas/glob v0.2.3
github.com/icza/gox v0.0.0-20200702115100-7dc3510ae515
github.com/kyoh86/xdg v1.2.0
github.com/mattn/go-mastodon v0.0.5-0.20210629151305-d39c10ba5e94

4
go.sum

@ -2,6 +2,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
@ -14,6 +16,8 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo
github.com/gdamore/tcell/v2 v2.3.3/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.3.11 h1:ECO6WqHGbKZ3HrSL7bG/zArMCmLaNr5vcjjMVnLHpzc=
github.com/gdamore/tcell/v2 v2.3.11/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=

60
linkoverlay.go

@ -2,6 +2,8 @@ package main
import (
"fmt"
"strconv"
"strings"
"github.com/gdamore/tcell/v2"
"github.com/mattn/go-mastodon"
@ -25,7 +27,13 @@ func NewLinkOverlay(app *App) *LinkOverlay {
l.List.ShowSecondaryText(false)
l.List.SetHighlightFullLine(true)
l.Flex.SetDrawFunc(app.Config.ClearContent)
l.TextBottom.SetText(ColorKey(app.Config.Style, "", "O", "pen"))
var items []string
items = append(items, ColorKey(app.Config.Style, "", "O", "pen"))
items = append(items, ColorKey(app.Config.Style, "", "Y", "ank"))
for _, cust := range app.Config.OpenCustom.OpenCustoms {
items = append(items, ColorKey(app.Config.Style, "", fmt.Sprintf("%d", cust.Index), cust.Name))
}
l.TextBottom.SetText(strings.Join(items, " "))
return l
}
@ -85,7 +93,7 @@ func (l *LinkOverlay) Open() {
return
}
if index < len(l.urls) {
openURL(l.app.Config.Media, l.urls[index].URL)
openURL(l.app.Config.Media, l.app.Config.OpenPattern, l.urls[index].URL)
return
}
mIndex := index - len(l.urls)
@ -110,6 +118,48 @@ func (l *LinkOverlay) Open() {
}
}
func (l *LinkOverlay) CopyToClipboard() {
text := l.GetURL()
if text != "" {
e := copyToClipboard(text)
if e == false {
l.app.UI.CmdBar.ShowError("Couldn't copy to clipboard.")
}
}
}
func (l *LinkOverlay) GetURL() string {
index := l.List.GetCurrentItem()
total := len(l.urls) + len(l.mentions) + len(l.tags)
if total == 0 || index >= total {
return ""
}
if index < len(l.urls) {
return l.urls[index].URL
}
mIndex := index - len(l.urls)
if mIndex < len(l.mentions) {
return l.mentions[mIndex].URL
}
tIndex := index - len(l.mentions) - len(l.urls)
if tIndex < len(l.tags) {
return l.tags[tIndex].URL
}
return ""
}
func (l *LinkOverlay) OpenCustom(index int) {
url := l.GetURL()
customs := l.app.Config.OpenCustom.OpenCustoms
for _, c := range customs {
if c.Index != index {
continue
}
openCustom(c.Program, c.Args, url)
return
}
}
func (l *LinkOverlay) InputHandler(event *tcell.EventKey) {
if event.Key() == tcell.KeyRune {
switch event.Rune() {
@ -119,6 +169,12 @@ func (l *LinkOverlay) InputHandler(event *tcell.EventKey) {
l.Prev()
case 'o', 'O':
l.Open()
case 'y', 'Y':
l.CopyToClipboard()
case '1', '2', '3', '4', '5':
s := string(event.Rune())
i, _ := strconv.Atoi(s)
l.OpenCustom(i)
case 'q', 'Q':
l.app.UI.SetFocus(LeftPaneFocus)
}

23
util.go

@ -13,6 +13,7 @@ import (
"strings"
"time"
"github.com/atotto/clipboard"
"github.com/gdamore/tcell/v2"
"github.com/icza/gox/timex"
"github.com/mattn/go-mastodon"
@ -103,7 +104,27 @@ func openEditor(app *tview.Application, content string) (string, error) {
return strings.TrimSpace(string(text)), nil
}
func openURL(conf MediaConfig, url string) {
func copyToClipboard(text string) bool {
if clipboard.Unsupported {
return false
}
clipboard.WriteAll(text)
return true
}
func openCustom(program string, args []string, url string) {
args = append(args, url)
exec.Command(program, args...).Start()
}
func openURL(conf MediaConfig, pc OpenPatternConfig, url string) {
for _, m := range pc.Patterns {
if m.Compiled.Match(url) {
args := append(m.Args, url)
exec.Command(m.Program, args...).Start()
return
}
}
args := append(conf.LinkArgs, url)
exec.Command(conf.LinkViewer, args...).Start()
}

Loading…
Cancel
Save