forked from nwg-piotr/nwg-drawer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- speed up parsing by not creating nearly as many strings. - fix basic whitespace handling. fixes nwg-piotr#4 goos: linux goarch: amd64 pkg: github.com/nwg-piotr/nwg-drawer cpu: AMD Ryzen 7 1800X Eight-Core Processor BenchmarkDesktopEntryParserOld-16 10000 146094 ns/op BenchmarkDesktopEntryParser-16 26097 43303 ns/op PASS ok github.com/nwg-piotr/nwg-drawer 3.090s
- Loading branch information
1 parent
c5e39f1
commit 57826c0
Showing
4 changed files
with
245 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
func parseDesktopEntryFileDeprecated(id string, path string) (entry desktopEntry, err error) { | ||
lines, err := loadTextFile(path) | ||
if err != nil { | ||
return entry, err | ||
} | ||
|
||
return parseDesktopEntryDeprecated(id, lines) | ||
} | ||
|
||
func parseDesktopEntryDeprecated(id string, lines []string) (entry desktopEntry, err error) { | ||
desktopID := id | ||
name := "" | ||
nameLoc := "" | ||
comment := "" | ||
commentLoc := "" | ||
icon := "" | ||
exec := "" | ||
categories := "" | ||
terminal := false | ||
noDisplay := false | ||
|
||
for _, l := range lines { | ||
if strings.HasPrefix(l, "[") && l != "[Desktop Entry]" { | ||
break | ||
} | ||
if strings.HasPrefix(l, "Name=") { | ||
name = strings.Split(l, "=")[1] | ||
continue | ||
} | ||
if strings.HasPrefix(l, fmt.Sprintf("Name[%s]=", strings.Split(*lang, "_")[0])) { | ||
nameLoc = strings.Split(l, "=")[1] | ||
continue | ||
} | ||
if strings.HasPrefix(l, "Comment=") { | ||
comment = strings.Split(l, "=")[1] | ||
continue | ||
} | ||
if strings.HasPrefix(l, fmt.Sprintf("Comment[%s]=", strings.Split(*lang, "_")[0])) { | ||
commentLoc = strings.Split(l, "=")[1] | ||
continue | ||
} | ||
if strings.HasPrefix(l, "Icon=") { | ||
icon = strings.Split(l, "=")[1] | ||
continue | ||
} | ||
if strings.HasPrefix(l, "Exec=") { | ||
exec = strings.Split(l, "Exec=")[1] | ||
disallowed := [2]string{"\"", "'"} | ||
for _, char := range disallowed { | ||
exec = strings.Replace(exec, char, "", -1) | ||
} | ||
continue | ||
} | ||
if strings.HasPrefix(l, "Categories=") { | ||
categories = strings.Split(l, "Categories=")[1] | ||
continue | ||
} | ||
if l == "Terminal=true" { | ||
terminal = true | ||
continue | ||
} | ||
if l == "NoDisplay=true" { | ||
noDisplay = true | ||
continue | ||
} | ||
} | ||
|
||
// if name[ln] not found, let's try to find name[ln_LN] | ||
if nameLoc == "" { | ||
nameLoc = name | ||
} | ||
if commentLoc == "" { | ||
commentLoc = comment | ||
} | ||
|
||
entry.DesktopID = desktopID | ||
entry.Name = name | ||
entry.NameLoc = nameLoc | ||
entry.Comment = comment | ||
entry.CommentLoc = commentLoc | ||
entry.Icon = icon | ||
entry.Exec = exec | ||
entry.Terminal = terminal | ||
entry.NoDisplay = noDisplay | ||
entry.Category = categories | ||
return entry, nil | ||
} | ||
|
||
func parseDesktopEntryFile(id string, path string) (e desktopEntry, err error) { | ||
o, err := os.Open(path) | ||
if err != nil { | ||
return e, err | ||
} | ||
defer o.Close() | ||
|
||
return parseDesktopEntry(id, o) | ||
} | ||
|
||
func parseDesktopEntry(id string, in io.Reader) (entry desktopEntry, err error) { | ||
cleanexec := strings.NewReplacer("\"", "", "'", "") | ||
entry.DesktopID = id | ||
localizedName := fmt.Sprintf("Name[%s]", strings.Split(*lang, "_")[0]) | ||
localizedComment := fmt.Sprintf("Comment[%s]", strings.Split(*lang, "_")[0]) | ||
scanner := bufio.NewScanner(in) | ||
scanner.Split(bufio.ScanLines) | ||
|
||
for scanner.Scan() { | ||
l := scanner.Text() | ||
if strings.HasPrefix(l, "[") && l != "[Desktop Entry]" { | ||
break | ||
} | ||
|
||
name, value := parseKeypair(l) | ||
if value == "" { | ||
continue | ||
} | ||
|
||
switch name { | ||
case "Name": | ||
entry.Name = value | ||
case localizedName: | ||
entry.NameLoc = value | ||
case "Comment": | ||
entry.Comment = value | ||
case localizedComment: | ||
entry.CommentLoc = value | ||
case "Icon": | ||
entry.Icon = value | ||
case "Categories": | ||
entry.Category = value | ||
case "Terminal": | ||
entry.Terminal, _ = strconv.ParseBool(value) | ||
case "NoDisplay": | ||
entry.NoDisplay, _ = strconv.ParseBool(value) | ||
case "Exec": | ||
entry.Exec = cleanexec.Replace(value) | ||
} | ||
} | ||
|
||
// if name[ln] not found, let's try to find name[ln_LN] | ||
if entry.NameLoc == "" { | ||
entry.NameLoc = entry.Name | ||
} | ||
if entry.CommentLoc == "" { | ||
entry.CommentLoc = entry.Comment | ||
} | ||
return entry, err | ||
} | ||
|
||
func parseKeypair(s string) (string, string) { | ||
if idx := strings.IndexRune(s, '='); idx > 0 { | ||
return strings.TrimSpace(s[:idx]), strings.TrimSpace(s[idx+1:]) | ||
} | ||
return s, "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package main | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
) | ||
|
||
var result desktopEntry | ||
|
||
func BenchmarkDesktopEntryParserOld(b *testing.B) { | ||
var entry desktopEntry | ||
for n := 0; n < b.N; n++ { | ||
entry, _ = parseDesktopEntryFileDeprecated("id", "./desktop-directories/game.directory") | ||
} | ||
result = entry | ||
} | ||
|
||
func BenchmarkDesktopEntryParser(b *testing.B) { | ||
var entry desktopEntry | ||
for n := 0; n < b.N; n++ { | ||
entry, _ = parseDesktopEntryFile("id", "./desktop-directories/game.directory") | ||
} | ||
result = entry | ||
} | ||
|
||
func TestWhitespaceHandling(t *testing.T) { | ||
const whitespace = `[Desktop Entry] | ||
Categories = Debugger; Development; Git; IDE; Programming; TextEditor; | ||
Comment = Editor for building and debugging modern web and cloud applications | ||
Exec = bash -c "code-insiders ~/Workspaces/Linux/Flutter.code-workspace" | ||
GenericName = Text Editor | ||
Icon = vscode-flutter | ||
Keywords = editor; IDE; plaintext; text; write; | ||
MimeType = application/x-shellscript; inode/directory; text/english; text/plain; text/x-c; text/x-c++; text/x-c++hdr; text/x-c++src; text/x-chdr; text/x-csrc; text/x-java; text/x-makefile; text/x-moc; text/x-pascal; text/x-tcl; text/x-tex; | ||
Name = VSCode Insiders with Flutter | ||
Name[pt] = VSCode Insiders com Flutter | ||
StartupNotify = true | ||
StartupWMClass = code - insiders | ||
Terminal = false | ||
NoDisplay = false | ||
Type = Application | ||
Version = 1.0` | ||
|
||
// entry, err := parseDesktopEntryDeprecated("id", strings.Split(whitespace, "\n")) | ||
*lang = "pt" | ||
entry, err := parseDesktopEntry("id", strings.NewReader(whitespace)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if entry.Name != "VSCode Insiders with Flutter" { | ||
t.Error("failed to parse desktop entry name") | ||
} | ||
|
||
if entry.NameLoc != "VSCode Insiders com Flutter" { | ||
t.Error("failed to parse localized name") | ||
} | ||
|
||
if entry.NoDisplay { | ||
t.Error("failed to parse desktop entry no display") | ||
} | ||
} |