From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Mark Oteiza Newsgroups: gmane.emacs.devel Subject: [PATCH] Add XDG utility library Date: Tue, 31 Jan 2017 19:26:06 -0500 Message-ID: <20170201002606.GA4224@holos.localdomain> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: blaine.gmane.org 1485908939 32402 195.159.176.226 (1 Feb 2017 00:28:59 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 1 Feb 2017 00:28:59 +0000 (UTC) User-Agent: Mutt/1.7.2+27 (e4ad1dc9bfbd) (2016-11-26) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Feb 01 01:28:55 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYin8-00089t-Jf for ged-emacs-devel@m.gmane.org; Wed, 01 Feb 2017 01:28:54 +0100 Original-Received: from localhost ([::1]:41906 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cYinE-0001kk-2W for ged-emacs-devel@m.gmane.org; Tue, 31 Jan 2017 19:29:00 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:39536) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cYikW-0008DO-H2 for emacs-devel@gnu.org; Tue, 31 Jan 2017 19:26:16 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cYikT-00083Q-CO for emacs-devel@gnu.org; Tue, 31 Jan 2017 19:26:12 -0500 Original-Received: from mail-qt0-x235.google.com ([2607:f8b0:400d:c0d::235]:36655) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cYikT-00083H-4H for emacs-devel@gnu.org; Tue, 31 Jan 2017 19:26:09 -0500 Original-Received: by mail-qt0-x235.google.com with SMTP id k15so250988361qtg.3 for ; Tue, 31 Jan 2017 16:26:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=udel-edu.20150623.gappssmtp.com; s=20150623; h=date:from:to:subject:message-id:mime-version:content-disposition :user-agent; bh=i1DgIDeJTTl32yF9vM9Z4j9tJAz+D7/TRqh8VSwz4K8=; b=M6C0awM7MbNGGASEQHBzl2CiSkJiLoXlqwva+Up1MV1nQCZXgIqkzfby7614uaA1+x 51vGuqZ0m35T7Skd88RMZkHB3ODNlrDPIWkd6Iw/PFAmXuzr4jR3yXEzoqt8waMq4ezP LAs85Y3uqPd0T/C+eK8RRu0JwLB6es/jacGcxgTMRM7Af2NSpmXOSXtUboV8BLlZ651o O83lKE3NFHWJXqGBC4WO19ktvbKSt34nIFggvL2yWs53jcxhPbyCnzc2HTsy7NBHW7XV pR3d8Mmu44AkkzQLr1XTIFmV4m5xD4XTd+NNpAGnQGBqkJFcsZcm2KJliuwBLepDic8G lDuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=i1DgIDeJTTl32yF9vM9Z4j9tJAz+D7/TRqh8VSwz4K8=; b=aesdAAG1e68SdPQAeTO0QyfpuhxX/PMppysGck1CwxIZlyVhiUDIxpM0f6OYnAdyua 4YtbuGlWP9P1XLJVvndMR9Flbc37W28gr6ytMQVDpN0YmemQYN6eCho+DiA+ITJWRTID KToVo9FoQDsRT6rD5TusQdpU+s5kBF9rxZmoEpVWGitmkexulfUsQg3HTz4x7kvOP/T7 m2s4AG1gZ8TCbIYZVG2nRB6d2x942JbOYueFeQEXMGHLyut2pXnfIRFGL0mUUrbQUwS+ CZNyoI6YoNQd6nYVaRgFsMuVdEcqqGgK0LLryeFquTVfAq2pTLnz2kT30E0myulYqbJ5 6D0A== X-Gm-Message-State: AIkVDXKvGMRlLXn2Ib1kfOddAFUU22pn+ToYujmae3xIzEFvAXXguOTHfoHcZdvbqvI+NBeN X-Received: by 10.200.2.8 with SMTP id k8mr48031qtg.163.1485908767942; Tue, 31 Jan 2017 16:26:07 -0800 (PST) Original-Received: from holos.localdomain (pool-173-67-40-97.bltmmd.fios.verizon.net. [173.67.40.97]) by smtp.gmail.com with ESMTPSA id r30sm16892762qtc.15.2017.01.31.16.26.06 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 31 Jan 2017 16:26:07 -0800 (PST) Original-Received: by holos.localdomain (Postfix, from userid 1000) id 72E3D60D6A; Tue, 31 Jan 2017 19:26:06 -0500 (EST) Content-Disposition: inline X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400d:c0d::235 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:211822 Archived-At: * etc/NEWS: Mention new library. * lisp/xdg.el: New file. --- Will otherwise commit in a week or so. etc/NEWS | 2 + lisp/xdg.el | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 lisp/xdg.el diff --git a/etc/NEWS b/etc/NEWS index 12ff21f39a..5f0f440b0b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -677,6 +677,8 @@ processes on exit. ** New Elisp data-structure library 'radix-tree'. +** New library 'xdg' with utilities for some XDG standards and specs. + * Incompatible Lisp Changes in Emacs 26.1 diff --git a/lisp/xdg.el b/lisp/xdg.el new file mode 100644 index 0000000000..51218e339d --- /dev/null +++ b/lisp/xdg.el @@ -0,0 +1,144 @@ +;;; xdg.el --- XDG specification and standard support -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; Author: Mark Oteiza +;; Created: 27 January 2017 +;; Keywords: files, data + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published +;; by the Free Software Foundation; either version 3 of the License, +;; or (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; Library providing some convenience functions for the following XDG +;; standards and specifications +;; +;; - XDG Base Directory Specification +;; - Thumbnail Managing Standard +;; - xdg-user-dirs configuration + +;;; Code: + + +;; XDG Base Directory Specification +;; https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +(defmacro xdg--dir-home (environ default-path) + (declare (debug (stringp stringp))) + (let ((env (make-symbol "env"))) + `(let ((,env (getenv ,environ))) + (if (or (null ,env) (not (file-name-absolute-p ,env))) + (expand-file-name ,default-path) + ,env)))) + +(defun xdg-config-home () + "Return the base directory for user specific configuration files." + (xdg--dir-home "XDG_CONFIG_HOME" "~/.config")) + +(defun xdg-cache-home () + "Return the base directory for user specific cache files." + (xdg--dir-home "XDG_CACHE_HOME" "~/.cache")) + +(defun xdg-data-home () + "Return the base directory for user specific data files." + (xdg--dir-home "XDG_DATA_HOME" "~/.local/share")) + +(defun xdg-runtime-dir () + "Return the value of $XDG_RUNTIME_DIR." + (getenv "XDG_RUNTIME_DIR")) + +(defun xdg-config-dirs () + "Return the config directory search path as a list." + (let ((env (getenv "XDG_CONFIG_DIRS"))) + (if (or (null env) (string= env "")) + '("/etc/xdg") + (parse-colon-path env)))) + +(defun xdg-data-dirs () + "Return the data directory search path as a list." + (let ((env (getenv "XDG_CONFIG_DIRS"))) + (if (or (null env) (string= env "")) + '("/usr/local/share/" "/usr/share/") + (parse-colon-path env)))) + + +;; Thumbnail Managing Standard +;; https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html + +(defun xdg-thumb-uri (filename) + "Return the canonical URI for FILENAME. +If FILENAME has absolute path /foo/bar.jpg, its canonical URI is +file:///foo/bar.jpg" + (concat "file://" (expand-file-name filename))) + +(defun xdg-thumb-name (filename) + "Return the appropriate thumbnail filename for FILENAME." + (concat (md5 (xdg-thumb-uri filename)) ".png")) + +(defun xdg-thumb-mtime (filename) + "Return modification time of FILENAME as integral seconds from the epoch." + (floor (float-time (nth 5 (file-attributes filename))))) + + +;; XDG User Directories +;; https://www.freedesktop.org/wiki/Software/xdg-user-dirs/ + +(defconst xdg-line-regexp + (eval-when-compile + (rx "XDG_" + (group-n 1 (or "DESKTOP" "DOWNLOAD" "TEMPLATES" "PUBLICSHARE" + "DOCUMENTS" "MUSIC" "PICTURES" "VIDEOS")) + "_DIR=\"" + (group-n 2 (or "/" "$HOME/") (*? (or (not (any "\"")) "\\\""))) + "\"")) + "Regexp matching non-comment lines in xdg-user-dirs config files.") + +(defvar xdg-user-dirs nil + "Alist of directory keys and values.") + +(defun xdg--user-dirs-parse-line () + "Return pair of user-dirs key to directory value in LINE, otherwise nil. +This should be called at the beginning of a line." + (skip-chars-forward "[:blank:]") + (when (and (/= (following-char) ?#) + (looking-at xdg-line-regexp)) + (let ((k (match-string 1)) + (v (match-string 2))) + (when (and k v) (cons k v))))) + +(defun xdg--user-dirs-parse-file (filename) + "Return alist of xdg-user-dirs from FILENAME." + (let (elt res) + (with-temp-buffer + (insert-file-contents filename) + (goto-char (point-min)) + (while (not (eobp)) + (setq elt (xdg--user-dirs-parse-line)) + (when (consp elt) (push elt res)) + (forward-line))) + res)) + +(defun xdg-user-dir (name) + "Return the path of user directory referred to by NAME." + (when (null xdg-user-dirs) + (setq xdg-user-dirs + (xdg--user-dirs-parse-file + (expand-file-name "user-dirs.dirs" (xdg-config-home))))) + (cdr (assoc name xdg-user-dirs))) + +(provide 'xdg) + +;;; xdg.el ends here -- 2.11.0