summary refs log tree commit diff
path: root/emacs/guix-utils.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs/guix-utils.el')
-rw-r--r--emacs/guix-utils.el160
1 files changed, 160 insertions, 0 deletions
diff --git a/emacs/guix-utils.el b/emacs/guix-utils.el
new file mode 100644
index 0000000000..c1fe1a3a38
--- /dev/null
+++ b/emacs/guix-utils.el
@@ -0,0 +1,160 @@
+;;; guix-utils.el --- General utility functions
+
+;; Copyright © 2014 Alex Kost <alezost@gmail.com>
+
+;; This file is part of GNU Guix.
+
+;; GNU Guix 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 Guix 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This file provides auxiliary general functions for guix.el package.
+
+;;; Code:
+
+;; (require 'cl-lib)
+
+(defvar guix-true-string "Yes")
+(defvar guix-false-string "–")
+(defvar guix-list-separator ", ")
+
+(defvar guix-time-format "%F %T"
+  "String used to format time values.
+For possible formats, see `format-time-string'.")
+
+(defun guix-get-string (val &optional face)
+  "Convert VAL into a string and return it.
+
+VAL can be an expression of any type.
+If VAL is t/nil, it is replaced with
+`guix-true-string'/`guix-false-string'.
+If VAL is list, its elements are concatenated using
+`guix-list-separator'.
+
+If FACE is non-nil, propertize returned string with this FACE."
+  (let ((str (cond
+              ((stringp val) val)
+              ((null val) guix-false-string)
+              ((eq t val) guix-true-string)
+              ((numberp val) (number-to-string val))
+              ((listp val) (mapconcat #'guix-get-string
+                                      val guix-list-separator))
+              (t (prin1-to-string val)))))
+    (if (and val face)
+        (propertize str 'face face)
+      str)))
+
+(defun guix-get-time-string (seconds)
+  "Return formatted time string from SECONDS.
+Use `guix-time-format'."
+  (format-time-string guix-time-format (seconds-to-time seconds)))
+
+(defun guix-get-one-line (str)
+  "Return one-line string from a multi-line STR."
+  (replace-regexp-in-string "\n" " " str))
+
+(defun guix-format-insert (val &optional face format)
+  "Convert VAL into a string and insert it at point.
+If FACE is non-nil, propertize VAL with FACE.
+If FORMAT is non-nil, format VAL with FORMAT."
+  (let ((str (guix-get-string val face)))
+    (insert (if format
+                (format format str)
+              str))))
+
+(defun guix-mapinsert (function sequence separator)
+  "Like `mapconcat' but for inserting text.
+Apply FUNCTION to each element of SEQUENCE, and insert SEPARATOR
+at point between each FUNCTION call."
+  (when sequence
+    (funcall function (car sequence))
+    (mapc (lambda (obj)
+            (insert separator)
+            (funcall function obj))
+          (cdr sequence))))
+
+(defun guix-insert-button (label face action &optional message
+                                 &rest properties)
+  "Make button with LABEL and insert it at point.
+Propertize button with FACE.
+ACTION is a function called when the button is pressed.  It
+should accept button as the argument.
+MESSAGE is a button message.
+See `insert-text-button' for the meaning of PROPERTIES."
+  (if (null label)
+      (guix-format-insert nil)
+    (apply #'insert-text-button
+           label
+           'face face
+           'action action
+           'follow-link t
+           'help-echo message
+           properties)))
+
+(defun guix-split-insert (val &optional face col separator)
+  "Convert VAL into a string, split it and insert at point.
+
+If FACE is non-nil, propertize returned string with this FACE.
+
+If COL is non-nil and result string is a one-line string longer
+than COL, split it into several short lines.
+
+Separate inserted lines with SEPARATOR."
+  (if (null val)
+      (guix-format-insert nil)
+    (let ((strings (guix-split-string (guix-get-string val) col)))
+      (guix-mapinsert (lambda (str) (guix-format-insert str face))
+                      strings
+                      (or separator "")))))
+
+(defun guix-split-string (str &optional col)
+  "Split string STR by lines and return list of result strings.
+If COL is non-nil and STR is a one-line string longer than COL,
+split it into several short lines."
+  (let ((strings (split-string str "\n *")))
+    (if (and col
+             (null (cdr strings))       ; if not multi-line
+             (> (length str) col))
+        (split-string (guix-get-filled-string str col) "\n")
+      strings)))
+
+(defun guix-get-filled-string (str col)
+  "Return string by filling STR to column COL."
+  (with-temp-buffer
+    (insert str)
+    (let ((fill-column col))
+      (fill-region (point-min) (point-max)))
+    (buffer-string)))
+
+(defun guix-completing-read-multiple (prompt table &optional predicate
+                                      require-match initial-input
+                                      hist def inherit-input-method)
+  "Same as `completing-read-multiple' but remove duplicates in result."
+  (cl-remove-duplicates
+   (completing-read-multiple prompt table predicate
+                             require-match initial-input
+                             hist def inherit-input-method)
+   :test #'string=))
+
+(defun guix-get-key-val (alist &rest keys)
+  "Return value from ALIST by KEYS.
+ALIST is alist of alists of alists ... which can be consecutively
+accessed with KEYS."
+  (let ((val alist))
+    (dolist (key keys val)
+      (setq val (cdr (assq key val))))))
+
+(provide 'guix-utils)
+
+;;; guix-utils.el ends here