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)))
|