;;;; oneliner.lisp -- defines a oneliner structure and functions for using it ;; 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 . (in-package :oneliners.cli) (defplist oneliner id name oneliner tags brief explanation runstyle createdat editedat createdby isflagged islocked) ;;; SUPPLEMENTARY GETTERS (defun get-positional-arguments (ol) "Collects the names of all positional arguments in the oneliner, prefix included." (remove-duplicates (sort (ppcre:all-matches-as-strings "#[1-9][0-9]*" (oneliner-oneliner ol)) #'string<) :test #'equal)) (defun get-named-arguments (ol) "Collects the names of all named arguments in the oneliner, prefix included" (remove-duplicates (ppcre:all-matches-as-strings "#[A-Za-z][A-Za-z0-9_]*" (oneliner-oneliner ol)) :test #'equal)) ;;; VALIDATION OF ONELINER SLOT VALUES (defun valid-oneliner-string-p (string) (and (not (find #\newline string)) (parse-oneliner-tags string))) (defun valid-brief-description-p (string) (<= (length string) 72)) (defun valid-runstyle-p (string) (member string '("auto" "manual") :test 'equalp)) (defun valid-oneliner-name-p (string) (or (equal string "") (and (< 2 (length string)) (ppcre:scan "^[a-zA-Z][a-zA-Z0-9_\-]+$" string)))) ;;; PRINTING (defun print-oneliner-result-for-user (ol) "Prints information about the oneliner to the terminal." (unless *term-width* (set-term-width)) ; setting here as a fallback, can set it elswere if desired. (let* ((title-line-format-str (concatenate 'string "~" (prin1-to-string *term-width*) "<[~a]~;~a~;~a~>~%")) (tags-line-format-string (concatenate 'string "~" (prin1-to-string *term-width*) "<~a~;by ~a ~a~>~%"))) (loop repeat *term-width* do (princ #\_)) (terpri) (format t title-line-format-str (oneliner-id ol) (or (oneliner-name ol) " ") (format nil "~:[ ~;⚠~]~:[ ~;🔒~]~:[ ~;📋~]" (oneliner-isflagged ol) (oneliner-islocked ol) (equalp "manual" (oneliner-runstyle ol)))) (format t tags-line-format-string (format nil "tags: ~{~a~^ ~}" (oneliner-tags ol)) (or (oneliner-createdby ol) " ") (if (oneliner-createdat ol) (datestring-of-universal-time (oneliner-createdat ol)) " ")) (loop for x from 0 to (length (oneliner-brief ol)) by *term-width* do (format t "~a~%" (string-trim '(#\space) (alexandria-2:subseq* (oneliner-brief ol) x (+ x *term-width*))))) (format t "~%~a~%~%" (oneliner-oneliner ol)))) ;;;; json serialization (defun oneliner-to-json-body (ol) "Takes a oneliner structure and produces some json suitable for sending to the server. ID and some other fields are omitted." (jonathan:to-json (list :oneliner (oneliner-oneliner ol) :tags (oneliner-tags ol) :brief (oneliner-brief ol) :name (if (plusp (length (oneliner-name ol))) (oneliner-name ol) :null) :explanation (oneliner-explanation ol) :runstyle (oneliner-runstyle ol))))