aboutsummaryrefslogtreecommitdiff
path: root/lib/util.lisp
blob: 441b2e0ad3775befb9cae06120def88da5839edd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
;;;; util.lisp -- bits and bobs

;; Copyright (C) 2022  Colin Okay

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU Affero General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.

;; This program 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 Affero General Public License for more details.

;; You should have received a copy of the GNU Affero General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.


(in-package :oneliners.cli)

(defun make-temp-file-name ()
  "Simply makes a file name for a temp file. Uses
UIOP:TEMPORARY-DIRECTORY for the directory."
  (namestring
   (merge-pathnames (format nil "~a~a" (gensym "oneliners") (get-universal-time))
                    (uiop:temporary-directory))))


(defun string-from-editor (&optional contents)
  (let ((filename (make-temp-file-name)))
    (when contents (a:write-string-into-file  contents filename :if-exists :supersede))
    (unwind-protect 
         (magic-ed:magic-ed filename :eval nil :output :string)
      (uiop:delete-file-if-exists filename))))


(defun executable-on-system-p (name)
  "A hack that heuristically determines whether or not an executable
with the provided name is on the system. It is not perfect. It
consults the environment PATH, and looks for the command in any of
the directories that appear in the value of that variable."
  #+unix
  (loop for path in (str:split ":" (uiop:getenv "PATH"))
        for directory = (cons :absolute
                              (cdr (str:split "/" path)))
          thereis (uiop:file-exists-p
                   (make-pathname :name name :directory directory))))

(defun parse-oneliner-tags (string)
  "Splits a string using consequtive whitespace as a separator, and
returns a set of strings that name executable system commands, as
determined by EXECUTABLE-ON-SYSTEM-P."
  (remove-duplicates
   (remove-if-not #'executable-on-system-p (ppcre:split " +" string))
   :test #'equal))

(defun print-to-file (printable-object pathname &optional (if-exists :supersede))
  "Prints an object to a file, ensuring that the containing directory exists first."
  (ensure-directories-exist pathname)
  (with-open-file (out pathname :direction :output :if-exists if-exists)
    (print printable-object out)))

(defun read-from-file (path)
  "Reads one form from the file at PATHNAME, if that file exists. Returns NIL if not."
  (when (uiop:file-exists-p path) 
    (with-open-file (input path)
      (read input))))

(defun true-or-false (what)
  "Returns the strings  \"true\" or \"false\" depending on whehter or not WHAT is null"
  (if what "true" "false"))


(defun datestring-of-universal-time (ut)
  (multiple-value-bind
        (sec min hour day month year)  (decode-universal-time ut)
    (declare (ignore sec min hour))
    (format nil "~a-~2,'0d-~2,'0d" year month day)))

(defmacro defplist (name &rest slots)
  (let* ((slots-names
           (loop for slot in slots
                 when (symbolp slot)
                   collect slot
                 when (consp slot)
                   collect (first slot)))
         (slot-defuns
           (loop for slot in slots-names
                 collect `(defun ,(intern (format nil "~a-~a"  name slot)) (,name)
                            (getf ,name ,(a:make-keyword slot)))
                 collect `(defun (setf ,(intern (format nil "~a-~a"  name slot))) (val ,name)
                            (setf (getf ,name ,(a:make-keyword slot)) val))))
         (make-name-defun
           `(defun ,(intern (format nil "MAKE-~a" name)) (&key ,@slots)
              (list ,@(loop for slot in slots-names
                            collect (a:make-keyword slot)
                            collect slot)))))
    `(progn
       ,make-name-defun
       ,@slot-defuns)))