From 8f9b59690660f85aeae675989fe9fe6b1b830445 Mon Sep 17 00:00:00 2001 From: Colin Okay Date: Fri, 11 Mar 2022 09:22:58 -0600 Subject: separated app from lib systems; added with-client-state --- lib/client.lisp | 50 ++++++++++++++++++++++++++++------------ lib/oneliner.lisp | 17 ++++---------- lib/state.lisp | 68 ++++++++++++++++++++++++++++++++++++++----------------- lib/util.lisp | 12 +++++++++- 4 files changed, 97 insertions(+), 50 deletions(-) (limited to 'lib') diff --git a/lib/client.lisp b/lib/client.lisp index f49201a..0c4c362 100644 --- a/lib/client.lisp +++ b/lib/client.lisp @@ -1,4 +1,4 @@ -;;;; main.lisp -- oneliners.cli entrypoint +;;;; main.lisp -- client actions ;; Copyright (C) 2022 Colin Okay @@ -16,7 +16,32 @@ ;; along with this program. If not, see . (in-package :oneliners.cli) -;;; CONFIG AND RESULTS FILE LOCATIONS +;;; SEARCHING FOR ONELINERS + +(defun search-for-oneliners (terms limit &optional not-flagged-p all-flagged-p newestp) + (assert (loop for term in terms never (find #\, term)) () "Search terms may not contain commas.") + (with-local-state () + (api:get--oneliners :tags (str:join "," terms) + :limit limit + :notflagged (true-or-false not-flagged-p) + :newest (true-or-false newestp) + :onlyflagged (true-or-false all-flagged-p)))) + +(defun search-for-oneliners (terms limit not-flagged-p all-flagged-p newestp) + + (set-term-width) + (ensure-config) + (let ((response + (api:request-with + (:host (host)) + (api:get--oneliners :tags (str:join "," terms) + :limit limit + :notflagged (if not-flagged-p "true" "false") + :newest (if newestp "true" "false") + :onlyflagged (if all-flagged-p "true" "false"))))) + (cache-and-print-search-response response))) + + (defvar *ol-output-timeout* 1) @@ -175,6 +200,13 @@ and, failing that, try to fetch from configured server." explanation))) (terpri)))) +(defun tags-from-oneliner (string) + "Splits a string using consequitive whitespace as a separator, +returning a set of tags" + (remove-duplicates + (remove-if-not #'executable-on-system-p (ppcre:split " +" string)) + :test #'equal)) + (defun add-new-oneliner () (ensure-config) @@ -433,19 +465,7 @@ and, failing that, try to fetch from configured server." (api:get--oneliners-all-flagged)))) (cache-and-print-search-response response)))) -(defun search-for-oneliners (terms limit not-flagged-p all-flagged-p newestp) - (assert (loop for term in terms never (find #\, term) )) - (set-term-width) - (ensure-config) - (let ((response - (api:request-with - (:host (host)) - (api:get--oneliners :tags (str:join "," terms) - :limit limit - :notflagged (if not-flagged-p "true" "false") - :newest (if newestp "true" "false") - :onlyflagged (if all-flagged-p "true" "false"))))) - (cache-and-print-search-response response))) + ;;; RUNNING THINGS IN THE SHELL. diff --git a/lib/oneliner.lisp b/lib/oneliner.lisp index e96ec22..48c78f6 100644 --- a/lib/oneliner.lisp +++ b/lib/oneliner.lisp @@ -1,4 +1,4 @@ -;;;; oneliner.lisp -- holds a local representation of onelienrs. +;;;; oneliner.lisp -- defines a oneliner structure and functions for using it ;; Copyright (C) 2022 Colin Okay @@ -32,8 +32,9 @@ isflagged islocked) +;;; SUPPLEMENTARY GETTERS -(defun collect-positional-arguments (ol) +(defun get-positional-arguments (ol) "Collects the names of all positional arguments in the oneliner, prefix included." (remove-duplicates (sort @@ -41,22 +42,12 @@ #'string<) :test #'equal)) -(defun collect-named-arguments (ol) +(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)) -(defun tags-from-oneliner (string) - "Splits a string using consequitive whitespace as a separator, -returning a set of tags" - (remove-duplicates - (remove-if-not #'executable-on-system-p (ppcre:split " +" string)) - :test #'equal)) - - - - ;;; VALIDATION OF ONELINER SLOT VALUES (defun valid-oneliner-string-p (string) diff --git a/lib/state.lisp b/lib/state.lisp index b0be21c..5bab3ed 100644 --- a/lib/state.lisp +++ b/lib/state.lisp @@ -15,7 +15,6 @@ ;; You should have received a copy of the GNU Affero General Public License ;; along with this program. If not, see . - (in-package :oneliners.cli) ;;; Config Struct @@ -32,6 +31,36 @@ (defvar *cache* nil "Holds cached oneliners as a list.") +;;; LOADING AND SAVING STATE + +(defun config-file () + "Returns the pahtname holding the location of the config file." + (merge-pathnames ".config/oneliners.config" (user-homedir-pathname))) + +(defun cached-oneliners-file () + "Returns the pathname holding the location of the cache." + (merge-pathnames ".cache/oneliners.cache" (user-homedir-pathname))) + +(defun wipe-cache () + "Deletes the cache, if present." + (uiop:delete-file-if-exists (cached-oneliners-file))) + +(defun write-config-to-disk () + (print-to-file *config* (config-file))) + +(defun write-cache-to-disk () + (print-to-file *cache* (cached-oneliners-file))) + +(defun read-config-file () + "Read a configuration from the location returned by CONFIG-FILE. NIL +if there is no such file" + (read-from-file (config-file))) + +(defun read-cache-file () + "Read the cache from the location returned by +CACHED-ONELINERS-FILE. NIL if there is no such file." + (read-from-file (cached-oneliners-file))) + ;;; GETTING AND SETTING STATE, DYNAMICALLY BOUND (defun merge-oneliners (new) @@ -56,23 +85,20 @@ (string #'oneliner-name)) :test #'equal)) -;;; LOADING AND SAVING STATE - -(defun config-file () - "Returns the pahtname holding the location of the config file." - (merge-pathnames ".config/oneliners.config" (user-homedir-pathname))) - -(defun cached-oneliners-file () - "Returns the pathname holding the location of the cache." - (merge-pathnames ".cache/oneliners.cache" (user-homedir-pathname))) - -(defun wipe-cache () - "Deletes the cache, if present." - (uiop:delete-file-if-exists (cached-oneliners-file))) - -(defun write-config-to-disk () - (print-to-file *config* (config-file))) - -(defun write-cache-to-disk () - (print-to-file *cache* (cached-oneliners-file))) - +;;; STATE LOADING MACRO + +(defmacro with-local-state (&body body) + "Binds the *config* and *cache* dynamic variables from disk, and +sets the api's *host* variable. If BODY produces no errors, the " + `(let* ((*config* (read-config-file)) + (*cache* (read-cache-file)) + (api::*host* (config-host *config*))) + (assert *host* () "ol must be configured with a server host.") + (handler-case + (progn + ,@body + ;; only if there is no error do we save the local state. + (write-cache-to-disk) + (write-config-to-disk))) + (error (e) + (format *error-output* "~a~%" e)))) diff --git a/lib/util.lisp b/lib/util.lisp index 31e1984..2a6d456 100644 --- a/lib/util.lisp +++ b/lib/util.lisp @@ -1,4 +1,4 @@ -;;;; util.lisp +;;;; util.lisp -- bits and bobs ;; Copyright (C) 2022 Colin Okay @@ -51,3 +51,13 @@ the directories that appear in the value of that variable." (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")) -- cgit v1.2.3