Support link entries
This commit is contained in:
parent
6970196048
commit
c9d02e13de
80
entry.go
80
entry.go
|
@ -3,21 +3,47 @@ package desktop
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type EntryType int
|
||||
|
||||
const (
|
||||
Unknown EntryType = iota
|
||||
Application
|
||||
Link
|
||||
Directory
|
||||
)
|
||||
|
||||
func (t EntryType) String() string {
|
||||
switch t {
|
||||
case Unknown:
|
||||
return "Unknown"
|
||||
case Application:
|
||||
return "Application"
|
||||
case Link:
|
||||
return "Link"
|
||||
case Directory:
|
||||
return "Directory"
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(t))
|
||||
}
|
||||
|
||||
var (
|
||||
entryHeader = []byte("[desktop entry]")
|
||||
entryType = []byte("type=")
|
||||
entryName = []byte("name=")
|
||||
entryGenericName = []byte("genericname=")
|
||||
entryComment = []byte("comment=")
|
||||
entryIcon = []byte("icon=")
|
||||
entryPath = []byte("path=")
|
||||
entryExec = []byte("exec=")
|
||||
entryURL = []byte("url=")
|
||||
entryTerminal = []byte("terminal=true")
|
||||
entryNoDisplay = []byte("nodisplay=true")
|
||||
entryHidden = []byte("hidden=true")
|
||||
|
@ -34,44 +60,18 @@ var quotes = map[string]string{
|
|||
`\\\\\\\\`: `\\\\`,
|
||||
}
|
||||
|
||||
func UnquoteExec(ex string) string {
|
||||
for qs, qr := range quotes {
|
||||
ex = strings.ReplaceAll(ex, qs, qr)
|
||||
}
|
||||
|
||||
return ex
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
Type EntryType
|
||||
Name string
|
||||
GenericName string
|
||||
Comment string
|
||||
Icon string
|
||||
Path string
|
||||
Exec string
|
||||
URL string
|
||||
Terminal bool
|
||||
}
|
||||
|
||||
func (e *Entry) String() string {
|
||||
name := ""
|
||||
if e.Name != "" {
|
||||
name = e.Name
|
||||
}
|
||||
if e.GenericName != "" {
|
||||
if name != "" {
|
||||
name += " / "
|
||||
}
|
||||
name += e.GenericName
|
||||
}
|
||||
|
||||
comment := "no comment"
|
||||
if e.Comment != "" {
|
||||
comment = e.Comment
|
||||
}
|
||||
|
||||
return fmt.Sprintf("{%s - %s}", name, comment)
|
||||
}
|
||||
|
||||
func (e *Entry) ExpandExec(args string) string {
|
||||
ex := e.Exec
|
||||
|
||||
|
@ -83,6 +83,14 @@ func (e *Entry) ExpandExec(args string) string {
|
|||
return ex
|
||||
}
|
||||
|
||||
func unquoteExec(ex string) string {
|
||||
for qs, qr := range quotes {
|
||||
ex = strings.ReplaceAll(ex, qs, qr)
|
||||
}
|
||||
|
||||
return ex
|
||||
}
|
||||
|
||||
func Parse(content io.Reader) (*Entry, error) {
|
||||
var (
|
||||
scanner = bufio.NewScanner(content)
|
||||
|
@ -109,6 +117,16 @@ func Parse(content io.Reader) (*Entry, error) {
|
|||
} else {
|
||||
break // Start of new section
|
||||
}
|
||||
} else if scannedBytesLen >= 6 && bytes.EqualFold(scannedBytes[0:5], entryType) {
|
||||
t := strings.ToLower(string(scannedBytes[5:]))
|
||||
switch t {
|
||||
case "application":
|
||||
entry.Type = Application
|
||||
case "link":
|
||||
entry.Type = Link
|
||||
case "directory":
|
||||
entry.Type = Directory
|
||||
}
|
||||
} else if scannedBytesLen >= 6 && bytes.EqualFold(scannedBytes[0:5], entryName) {
|
||||
entry.Name = string(scannedBytes[5:])
|
||||
} else if scannedBytesLen >= 13 && bytes.EqualFold(scannedBytes[0:12], entryGenericName) {
|
||||
|
@ -120,7 +138,9 @@ func Parse(content io.Reader) (*Entry, error) {
|
|||
} else if scannedBytesLen >= 6 && bytes.EqualFold(scannedBytes[0:5], entryPath) {
|
||||
entry.Path = string(scannedBytes[5:])
|
||||
} else if scannedBytesLen >= 6 && bytes.EqualFold(scannedBytes[0:5], entryExec) {
|
||||
entry.Exec = UnquoteExec(string(scannedBytes[5:]))
|
||||
entry.Exec = unquoteExec(string(scannedBytes[5:]))
|
||||
} else if scannedBytesLen >= 5 && bytes.EqualFold(scannedBytes[0:4], entryURL) {
|
||||
entry.URL = string(scannedBytes[4:])
|
||||
} else if scannedBytesLen == 13 && bytes.EqualFold(scannedBytes, entryTerminal) {
|
||||
entry.Terminal = true
|
||||
} else if (scannedBytesLen == 14 && bytes.EqualFold(scannedBytes, entryNoDisplay)) || (scannedBytesLen == 11 && bytes.EqualFold(scannedBytes, entryHidden)) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package desktop
|
|||
import (
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -12,15 +13,14 @@ type testData struct {
|
|||
}
|
||||
|
||||
var testCases = []*testData{
|
||||
{Filename: "alacritty.desktop", Entry: &Entry{Name: "Alacritty", GenericName: "Terminal", Comment: "A cross-platform, GPU enhanced terminal emulator", Icon: "Alacritty", Path: "/home/test", Exec: "alacritty", Terminal: false}},
|
||||
{Filename: "vim.desktop", Entry: &Entry{Name: "Vim", GenericName: "Text Editor", Comment: "Edit text files", Icon: "gvim", Exec: "vim %F", Terminal: true}},
|
||||
{Filename: "nodisplay.desktop", Entry: nil},
|
||||
{Filename: "app-alacritty.desktop", Entry: &Entry{Type: Application, Name: "Alacritty", GenericName: "Terminal", Comment: "A cross-platform, GPU enhanced terminal emulator", Icon: "Alacritty", Path: "/home/test", Exec: "alacritty"}},
|
||||
{Filename: "app-vim.desktop", Entry: &Entry{Type: Application, Name: "Vim", GenericName: "Text Editor", Comment: "Edit text files", Icon: "gvim", Exec: "vim %F", Terminal: true}},
|
||||
{Filename: "app-vim-nodisplay.desktop", Entry: nil},
|
||||
{Filename: "link-google.desktop", Entry: &Entry{Type: Link, Name: "Link to Google", Icon: "text-html", URL: "https://google.com"}},
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
for _, c := range testCases {
|
||||
expected := c.Entry
|
||||
|
||||
f, err := os.OpenFile("test/"+c.Filename, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -32,40 +32,8 @@ func TestParse(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if entry == nil || expected == nil {
|
||||
if entry != expected {
|
||||
t.Fatalf("%s: entry incorrect: got %#v, want %#v", f.Name(), entry, expected)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Name != expected.Name {
|
||||
t.Fatalf("%s: name incorrect: got %s, want %s", f.Name(), entry.Name, expected.Name)
|
||||
}
|
||||
|
||||
if entry.GenericName != expected.GenericName {
|
||||
t.Fatalf("%s: generic name incorrect: got %s, want %s", f.Name(), entry.GenericName, expected.GenericName)
|
||||
}
|
||||
|
||||
if entry.Comment != expected.Comment {
|
||||
t.Fatalf("%s: comment incorrect: got %s, want %s", f.Name(), entry.Comment, expected.Comment)
|
||||
}
|
||||
|
||||
if entry.Icon != expected.Icon {
|
||||
t.Fatalf("%s: icon incorrect: got %s, want %s", f.Name(), entry.Icon, expected.Icon)
|
||||
}
|
||||
|
||||
if entry.Path != expected.Path {
|
||||
t.Fatalf("%s: Path incorrect: got %s, want %s", f.Name(), entry.Path, expected.Path)
|
||||
}
|
||||
|
||||
if entry.Exec != expected.Exec {
|
||||
t.Fatalf("%s: Exec incorrect: got %s, want %s", f.Name(), entry.Exec, expected.Exec)
|
||||
}
|
||||
|
||||
if entry.Terminal != expected.Terminal {
|
||||
t.Fatalf("%s: terminal incorrect: got %v, want %v", f.Name(), entry.Terminal, expected.Terminal)
|
||||
if !reflect.DeepEqual(entry, c.Entry) {
|
||||
t.Fatalf("%s: entry incorrect: got %#v, want %#v", f.Name(), entry, c.Entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=Link to Google
|
||||
Type=Link
|
||||
URL=https://google.com
|
||||
Icon=text-html
|
Loading…
Reference in New Issue