Support link entries

This commit is contained in:
Trevor Slocum 2019-07-17 09:34:11 -07:00
parent 6970196048
commit c9d02e13de
6 changed files with 63 additions and 69 deletions

View File

@ -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)) {

View File

@ -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)
}
}
}

6
test/link-google.desktop Normal file
View File

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Name=Link to Google
Type=Link
URL=https://google.com
Icon=text-html