Giter Site home page Giter Site logo

standardpaths's Introduction

Standard paths

D library for getting standard paths (e.g. Pictures, Music, Documents and also generic configuration and data paths). Inspired by QStandardPaths from Qt.

Build Status Windows Build Status

Online documentation

Platform support

Works on Freedesktop (GNU/Linux, FreeBSD, etc.), Windows and OS X.

Running examples

Prints some standard paths to stdout.

dub examples/printdirs.d

On OSX it also can be built to use Cocoa instead of Carbon:

dub --single examples/printdirs.d --override-config=standardpaths/cocoa

Get path of given type, verify it exists or create if it does not.

dub examples/getpath.d --verify --create templates

Use Cocoa instead of Carbon on OSX:

dub --single examples/getpath.d --override-config=standardpaths/cocoa -- --create music

With subfolder:

dub examples/getpath.d --subfolder=MyLittleCompany/MyLittleApplication data

Use cases

Some code snippets showing how standardpaths library is supposed to be used.

Building file dialogs

Let's say you have some fancy FileDialog class and you want to provide shortcuts to standard user directories to improve experience. Your code may look like this:

import standardpaths;
import std.file;
import std.stdio;

void showFileDialog()
{
    auto fileDialog = new FileDialog;
    auto folderFlag = FolderFlag.verify;

    string[] paths = [
        homeDir(),
        writablePath(StandardPath.desktop, folderFlag),
        writablePath(StandardPath.downloads, folderFlag),
        writablePath(StandardPath.documents, folderFlag),
        writablePath(StandardPath.pictures, folderFlag),
        writablePath(StandardPath.music, folderFlag),
        writablePath(StandardPath.videos, folderFlag),
        writablePath(StandardPath.templates, folderFlag),
        writablePath(StandardPath.publicShare, folderFlag)
    ];
    foreach(path; paths) {
        if (path.length) {
            string label = path.baseName();
            fileDialog.addPath(label, path);
        }
    }
    fileDialog.show();
}

Writing configuration files

Usually your application will have some configuration file (or files) to store user's preferences and settings. That's where you could use StandardPath.config path. While the library returns generic paths for configuration, data and cache, you want to have separate folders specially for your application, so you will not accidentally read or modify files used by other programs. Usually these paths are built by concatenating of generic path, organization name and application name.

//You may have these as constants somewhere in your code
enum organizationName = "MyLittleCompany";
enum applicationName = "MyLittleApplication";

import standardpaths;
import std.stdio;
import std.path;

void saveSettings(const Config config)
{
    string configDir = writablePath(StandardPath.config, buildPath(organizationName, applicationName), FolderFlag.create);
    if (!configDir.length) {
        throw new Exception("Could not create config directory");
    }
    string configFile = buildPath(configDir, "config.conf");

    auto f = File(configFile, "w"); 
    // write settings
    writeln("Settings saved!");
}

Reading configuration files

Since one can save settings it also should be able to read them. Before the first start application does not have any user-specific settings, though it may provide some global default settings upon installing. It's up to developer to decide how to read configs, e.g. whether to read the first found file only or to merge settings from all found config consequentially.

Config readSettings()
{
    string[] configDirs = standardPaths(StandardPath.config, buildPath(organizationName, applicationName));

    foreach(configDir; configDirs) {
        string configFile = buildPath(configDir, "config.conf");
        if (configFile.exists) {
            auto f = File(configFile, "r");
            Config config;
            //read settings...
            return config;//consider using of the first found file
        }
    }
}

Implementation details

Freedesktop

On freedesktop systems (GNU/Linux, FreeBSD, etc.) library follows XDG Base Directory Specification and also provides behavior similiar to xdg-user-dirs.

Windows

On Windows it utilizes SHGetKnownFolderPath or SHGetSpecialFolderPath as fallback.

Mac OS X

Depending on configuration the library uses FSFindFolder from Carbon framework or URLForDirectory from Cocoa. See here.

standardpaths's People

Contributors

freeslave avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

etcimon drahosj

standardpaths's Issues

Standardpaths on OS X

The problem is simple: I don't have Mac machine at home, so I can't experiment with Mac OS X version of library.

Once I got chance to use Macbook at work and wrote this small application in C:

#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>

void printPath(short domain, OSType type) {
    FSRef ref;
    OSErr err = FSFindFolder(domain, type, false, &ref);
    if (err) {
        printf("Error!\n");
    } else {
        unsigned char path[2048];
        if (FSRefMakePath(&ref, path, sizeof(path)) == noErr) {
            printf("%s\n", (const char*)path);
        } else {
            printf("Error making path\n");
        }
    }
}

int main()
{
    short domains[2] = {kOnAppropriateDisk, kUserDomain};

    OSType types[] = {kDocumentsFolderType, kMusicDocumentsFolderType, kPictureDocumentsFolderType, 
        kMovieDocumentsFolderType, kFontsFolderType, kDesktopFolderType, 
        kPreferencesFolderType, kApplicationsFolderType, kTemporaryFolderType, 
        kApplicationSupportFolderType, kCachedDataFolderType
    };

    int i, j;
    for (i = 0; i<2; ++i) {
        for (j = 0; j<sizeof(types)/sizeof(OSType); ++j) {
            printPath(domains[i], types[j]);
        }
    }


    return 0;
}

It should be compiled with clang -framework Carbon if I recall correctly.
Then I wrote some OSX code for standardpaths library using the same approach, but did not try it, since could not find Carbon binding for D. Actually I'm not even sure that it's right way to use Carbon nowadays (clang claims FSFindFolder is deprecated). So I need help of experienced OS X developers here.

Decide on names

Currently library has StandardPath enum and writablePath and standardPaths** functions. Qt QStandardPaths uses StandardLocation, writableLocations and standardLocations. We should choose which names are better.

Example isn't works

$ dub run :printdirs --build=release
Building package standardpaths:printdirs in /home/denizzz/standardpaths/examples/printdirs/
Non-optional dependency xdgpaths of standardpaths not found in dependency tree!?.

Missing user font paths on Windows

AuburnSounds/printed#39

On my machine, there are user fonts in C:\Users\<user>\AppData\Local\Microsoft\Windows\fonts
however only c:\Windows\fonts is returned by standardPaths(StandardPath.fonts), twice.

This leads to errors downstream as people instal fonts just for them and not globally.

Paths including terminating nulls

writablePath() appears to include a null at the end of the returned string. Nulls are illegal characters in windows paths, which makes the result more difficult to use.

Platform: Windows 10 (64-bit)
dmd 2.070.0

Should Shell32 on Windows be required by default?

Currently Shell32 is loaded dynamically by default. Linking is possible via compile-time version switch.

Both dmd and gdc link executable against Shell32 (according to Dependency Walker), so it probably does not make sense to load the library at runtime. Need to check if ldc does this too.

Font paths on X11

Font paths on X11 are determined from fonts.conf files from various locations ($XDG_CONFIG_DIR/fontconfig/fonts.conf and /etc/fonts/fonts.conf).
Each file can define many paths so it's not clear which path should be returned by writablePath function. Currently it just return the first path from $XDG_CONFIG_DIR/fontconfig/fonts.conf, but it may be not writable.
Probably Font paths should not be present in this library at all, or at least not in StandardPath enum (i.e. make separate function for retrieving font paths). We also can just return ~/.fonts

Fallbacks for xdg-user-dirs

Should we use hard-coded fallbacks for xdg user directories? Or read them from /etc/xdg/user-dirs.defaults? xdg-user-dirs page does not really state anything about the right behavior since it's application, not specification.

Edit: added reading from /etc/xdg/user-dirs.defaults. Fallbacks are provided only for certain paths the same way as in xdg-user-dirs-update utility.

XDG_RUNTIME_DIR on FreeBSD

Does FreeBSD (and other BSD systems) have something like /run/user/$UID directory on Linux? XDG says it's directory for runtime files, but there's no such environment variable on my freebsd installation.

Cached paths

Should we provide some kind of caching for retrieved paths? There're some paths that may take long time to obtain (e.g. fontconfig on freedesktop needs reading of xml files).

I see three options:

  1. Provide caching for some "heavy" paths or for all of them using static variables. But it raises multithreading problems and makes library unresponsive to environment changes (e.g. fontconfig was changed while application runs).
  2. Provide some special class/struct that implements paths' caching, while leaving "non-cached" behavior for functions.
  3. Don't care about issue and just let user to implement his own caching model.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.