diff --git a/.travis.yml b/.travis.yml index a9219fa..33af179 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,11 @@ matrix: - d: dmd-2.065.0 - d: gdc-4.8.2 - d: ldc-0.14.0 + +install: + - wget -O doveralls "https://github.com/ColdenCullen/doveralls/releases/download/v1.1.6/doveralls_linux_travis" + - chmod +x doveralls + +script: + - dub test -b unittest-cov --compiler=${DC} + - ./doveralls diff --git a/README.md b/README.md index f1eeb80..79f6a8f 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The library is crossplatform for the most part, though there's little sense to u * Can rewrite desktop files preserving all comments and the original order of groups. * Retrieving [Desktop file ID](http://standards.freedesktop.org/desktop-entry-spec/latest/ape.html). * Support for [Additional application actions](http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s10.html). -* Determining default terminal command to run applications with Terminal=true. +* Determining default terminal command to run applications with Terminal=true. Note that default terminal detector may not work properly on particular system since there's no standard way to find default terminal emulator that would work on every distribution and desktop environment. ### Missing features @@ -58,12 +58,13 @@ import std.process; import desktopfile; string filePath = ...; -string[] arguments = ...; +string[] urls = ...; try { auto df = new DesktopFile(filePath); - string locale = environment.get("LC_CTYPE", environment.get("LC_ALL", environment.get("LANG"))); //Detect current locale. + //Detect current locale. + string locale = environment.get("LC_CTYPE", environment.get("LC_ALL", environment.get("LANG"))); string name = df.localizedName(locale); //Specific name of the application. string genericName = df.localizedGenericName(locale); //Generic name of the application. Show it in menu under the specific name. @@ -72,7 +73,7 @@ try { string iconName = df.iconName(); //Freedesktop icon name. if (df.hidden()) { - //User uninstalled desktop file and it should be shown in menus. + //User uninstalled desktop file and it should not be shown in menus. } string[] onlyShowIn = df.onlyShowIn().array; //If not empty, show this application only in listed desktop environments. @@ -84,13 +85,14 @@ try { foreach(action; df.byAction()) { //Supported actions. string actionName = action.name(); + action.start(locale); } if (df.type() == DesktopFile.Type.Application) { //This is application string commandLine = df.execString(); //Command line pattern used to start the application. try { - df.startApplication(arguments); //Start application using given arguments. It will be automatically started in terminal emulator if required. + df.startApplication(urls, locale); //Start application using given arguments and specified locale. It will be automatically started in terminal emulator if required. } catch(ProcessException e) { //Failed to start the application. stderr.writeln(e.msg); @@ -170,4 +172,9 @@ Example using cmd on Windows (KDE installed): set KDE_SHARE="%SYSTEMDRIVE%\ProgramData\KDE\share" dub run desktopfile:desktoptest -- %KDE_SHARE%\applications %KDE_SHARE%\templates %KDE_SHARE%\desktop-directories %KDE_SHARE%\autostart - \ No newline at end of file +### Shoot desktop file + +Uses the alternative way of starting desktop file. Instead of constructing DesktopFile object it just starts the application or opens link after read enough information from file. + + dub run desktopfile:shootdesktop -- $HOME/Desktop/vlc.desktop + diff --git a/dub.json b/dub.json index 7dc0600..28cb63e 100644 --- a/dub.json +++ b/dub.json @@ -5,7 +5,7 @@ "copyright": "Copyright © 2015, Roman Chistokhodov", "authors": ["Roman Chistokhodov"], "dependencies": { - "inilike": "~>0.3.0" + "inilike": "~>0.4.0" }, "targetName" : "desktopfile", "targetPath" : "lib", diff --git a/dub.selections.json b/dub.selections.json index 698d120..9e5e2f3 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -1,7 +1,6 @@ { "fileVersion": 1, "versions": { - "standardpaths": "0.2.0", - "inilike": "0.3.0+commit.4.g4cb3e80" + "inilike": "0.4.0" } } \ No newline at end of file diff --git a/examples/desktoptest/dub.selections.json b/examples/desktoptest/dub.selections.json index 698d120..cbd4e38 100644 --- a/examples/desktoptest/dub.selections.json +++ b/examples/desktoptest/dub.selections.json @@ -2,6 +2,6 @@ "fileVersion": 1, "versions": { "standardpaths": "0.2.0", - "inilike": "0.3.0+commit.4.g4cb3e80" + "inilike": "0.4.0" } } \ No newline at end of file diff --git a/examples/desktoputil/dub.selections.json b/examples/desktoputil/dub.selections.json index 698d120..9e5e2f3 100644 --- a/examples/desktoputil/dub.selections.json +++ b/examples/desktoputil/dub.selections.json @@ -1,7 +1,6 @@ { "fileVersion": 1, "versions": { - "standardpaths": "0.2.0", - "inilike": "0.3.0+commit.4.g4cb3e80" + "inilike": "0.4.0" } } \ No newline at end of file diff --git a/examples/shootdesktop/dub.json b/examples/shootdesktop/dub.json index c74f6d8..805f640 100644 --- a/examples/shootdesktop/dub.json +++ b/examples/shootdesktop/dub.json @@ -1,12 +1,12 @@ { - "name": "shootdesktop", - "description": "A minimal D application.", - "copyright": "Copyright © 2015, freeslave", - "authors": ["freeslave"], - "dependencies": { - "desktopfile" : "*" - }, - "targetPath" : "bin", + "name": "shootdesktop", + "description": "A minimal D application.", + "copyright": "Copyright © 2015, freeslave", + "authors": ["freeslave"], + "dependencies": { + "desktopfile" : "*" + }, + "targetPath" : "bin", "targetType" : "executable", "targetName" : "shootdesktop", } diff --git a/examples/shootdesktop/dub.selections.json b/examples/shootdesktop/dub.selections.json index 7837ace..cbd4e38 100644 --- a/examples/shootdesktop/dub.selections.json +++ b/examples/shootdesktop/dub.selections.json @@ -1,6 +1,7 @@ { "fileVersion": 1, "versions": { - "inilike": "0.3.0+commit.5.g496b71a" + "standardpaths": "0.2.0", + "inilike": "0.4.0" } -} +} \ No newline at end of file diff --git a/examples/shootdesktop/source/app.d b/examples/shootdesktop/source/app.d index 04f244b..98e8ac6 100644 --- a/examples/shootdesktop/source/app.d +++ b/examples/shootdesktop/source/app.d @@ -5,40 +5,40 @@ import desktopfile.utils; int main(string[] args) { - bool onlyExec; - bool notFollow; - - getopt( - args, - "onlyExec", "Only start applications, don't open links", &onlyExec, - "notFollow", "Don't follow desktop files", ¬Follow); - - - string fileName; - if (args.length > 1) { - fileName = args[1]; - } else { - stderr.writeln("Must provide path to desktop file"); - return 1; - } - - ShootOptions options; - - if (onlyExec) { - options.flags = options.flags & ~ShootOptions.Link; - } - - if (notFollow) { - options.flags = options.flags & ~ ShootOptions.FollowLink; - } - - try { - shootDesktopFile(fileName, options); - } - catch(Exception e) { - stderr.writeln(e.msg); - return 1; - } - - return 0; + bool onlyExec; + bool notFollow; + + getopt( + args, + "onlyExec", "Only start applications, don't open links", &onlyExec, + "notFollow", "Don't follow desktop files", ¬Follow); + + + string fileName; + if (args.length > 1) { + fileName = args[1]; + } else { + stderr.writeln("Must provide path to desktop file"); + return 1; + } + + ShootOptions options; + + if (onlyExec) { + options.flags = options.flags & ~ShootOptions.Link; + } + + if (notFollow) { + options.flags = options.flags & ~ ShootOptions.FollowLink; + } + + try { + shootDesktopFile(fileName, options); + } + catch(Exception e) { + stderr.writeln(e.msg); + return 1; + } + + return 0; } diff --git a/source/desktopfile/utils.d b/source/desktopfile/utils.d index 82ca388..8a4573a 100644 --- a/source/desktopfile/utils.d +++ b/source/desktopfile/utils.d @@ -352,7 +352,7 @@ string[] getTerminalCommand() nothrow @trusted } else { string toReturn; try { - foreach(path; splitter(environment.get("PATH"), ':')) { + foreach(path; std.algorithm.splitter(environment.get("PATH"), ':')) { toReturn = checkExecutable(buildPath(path, name)); if (toReturn.length) { return toReturn; @@ -409,7 +409,7 @@ struct ShootOptions /** * Urls to pass to the program is desktop file points to application. - * Empry by default. + * Empty by default. */ string[] urls; @@ -420,26 +420,32 @@ struct ShootOptions string locale; /** - * Function that should be used to open url if desktop file is link. + * Delegate that should be used to open url if desktop file is link. + * To set static function use std.functional.toDelegate. * If it's null shootDesktopFile will use xdg-open. */ void delegate(string) opener = null; /** - * Function that should be used to get terminal command. + * Delegate that should be used to get terminal command. + * To set static function use std.functional.toDelegate. * If it's null, shootDesktopFile will use getTerminalCommand. * See_Also: getTerminalCommand */ - string[] delegate() terminalDetector = null; + const(string)[] delegate() terminalDetector = null; } /** * Read the desktop file and run application or open link depending on the type of the given desktop file. * Params: * reader = IniLikeReader constructed from range of strings using iniLikeRangeReader - * fileName = file name of desktop file where data read from. + * fileName = file name of desktop file where data read from. It's optional, but can be set to the file name from which contents IniLikeReader was constructed. * options = options that set behavior of the function. * Use this function to execute desktop file fast, without creating of DesktopFile instance. + * Throws: + * ProcessException on failure to start the process. + * DesktopExecException if exec string is invalid. + * Exception on other errors. * See_Also: ShootOptions */ @trusted void shootDesktopFile(IniLikeReader)(IniLikeReader reader, string fileName = null, ShootOptions options = ShootOptions.init) @@ -449,6 +455,8 @@ struct ShootOptions string iconName, name, execString, url, workingDirectory; bool terminal; + string bestLocale; + foreach(g; reader.byGroup) { if (g.name == "Desktop Entry") { foreach(e; g.byEntry) { @@ -465,10 +473,11 @@ struct ShootOptions case "Path": workingDirectory = value; break; case "Terminal": terminal = isTrue(value); break; default: { - //TODO: Choosing the most appropriate locale - auto lt = separateFromLocale(key); - if (name.empty && lt[0] == "Name" && (lt[1].empty || lt[1] == options.locale)) { - name = value; + auto kl = separateFromLocale(key); + if (kl[0] == "Name") { + auto lv = chooseLocalizedValue(options.locale, kl[1], value, bestLocale, name); + bestLocale = lv[0]; + name = lv[1]; } } break;