git.fiddlerwoaroof.com
it-lookup.lisp
dfb60766
 ;;;; it-lookup.lisp
e9a3dbce
 
dfb60766
 (in-package #:it-lookup)
33870e9a
 (declaim (optimize (debug 3)))
e9a3dbce
 
dfb60766
 ;;; "it-lookup" goes here. Hacks and glory await!
e9a3dbce
 
 (defparameter *post-url*  "http://www.corpusthomisticum.org/it/index.age")
 
 (defparameter *cookie-jar* (make-instance 'drakma:cookie-jar))
 
33870e9a
 (defun run-query (results)
   (with-accessors ((query query) (page page)) results
     (drakma:http-request *post-url*
                          :method :POST
                          :parameters `(("text" . ,query)
                                        ("Form.option.concordances" . "concordances")
                                        ("results.currentPage" . ,(prin1-to-string page)))
                          :cookie-jar *cookie-jar*)))
e9a3dbce
 
 (defclass it-case ()
   ((reference :initarg :reference :accessor case-reference)
    (text :initarg :text :accessor case-text)))
 
33870e9a
 (defun make-adjustable-vector (&optional (base-size 10))
   (make-array base-size :adjustable t :fill-pointer 0))
 
 (defun to-adjustable-vector (values)
   (let ((els (length values)))
     (make-array els
                 :adjustable t
                 :fill-pointer els
                 :initial-contents values)))
 
 (defclass it-results ()
   ((%query :initarg :query :accessor query :initform (make-adjustable-vector))
    (%page :initarg :page :accessor page :initform 1)
    (%cases :initarg :cases :accessor cases)))
 
e9a3dbce
 (defmethod initialize-instance :after ((object it-case) &key)
   (with-slots (reference text) object
     (when (arrayp reference)
       (setf reference (elt reference 0)))
     (when (plump:element-p reference)
       (setf reference (plump-dom:text reference)))
     (setf text (subseq text (+ (search reference text) (length reference))))
33870e9a
     (setf reference (string-right-trim '(#\space) reference))))
e9a3dbce
 
 (defmacro make-constructor (class &rest initargs)
   (let ((initarg-syms (mapcar #'(lambda (x) x (gensym)) initargs)))
     `(defun ,(intern (concatenate 'string (string 'make-) (string class))) ,initarg-syms
        (make-instance ',class ,@(loop for initarg in initargs
                                      for sym in initarg-syms
                                      nconc (list initarg sym))))))
 
 (make-constructor it-case :reference :text)
33870e9a
 (make-constructor it-results :query :cases)
 
 (defun parse-results (results query-result)
   (setf (cases results)
         (lquery:$ (initialize query-result)
                   "p[title]"
                   (:combine ".ref" (text))
                   (map-apply #'make-it-case))))
e9a3dbce
 
33870e9a
 (defgeneric format-reference (it-case stream)
   (:method ((it-case it-case) stream)
    (princ (case-reference it-case) stream)
    (fresh-line stream)))
 
 (defparameter *underlying-stream* nil)
 (defun get-real-stream (&optional default)
   (or *underlying-stream* default))
e9a3dbce
 
 (defun format-result (parsed-result &optional (stream t))
33870e9a
   (let ((real-stream stream))
e9a3dbce
     (pprint-logical-block (stream nil)
33870e9a
       (let ((*underlying-stream* real-stream))
         (format-reference parsed-result stream))
e9a3dbce
       (pprint-indent :block 4 stream)
       (pprint-newline :mandatory stream)
33870e9a
       (with-slots (text) parsed-result
         (pprint-logical-block (stream (tokens text))
           (loop
             (princ (pprint-pop) stream)
             (pprint-exit-if-list-exhausted)
             (princ #\space stream)
             (pprint-newline :fill stream)))))))
e9a3dbce
 
 (defun format-results (parsed-results &optional (stream t))
   (fresh-line stream)
33870e9a
   (loop :for parsed-result :across parsed-results
         :do (format-result parsed-result stream)
e9a3dbce
         :do (terpri stream)))
 
 (defmacro compose-funcs ((&rest funcs) &rest args)
   `(funcall (compose ,@funcs) ,@args))
 
 (defun main (args)
33870e9a
   (let ((results (make-instance 'it-results
                                 :query nil)))
 
     (format *terminal-io* "~&Index Thomisticus Query Utility v0.1~%")
 
     (when (cadr args)
       (setf (query results) (cadr args)))
 
     (mainloop results)))
 
 (defun mainloop (results)
e9a3dbce
   (handler-case
33870e9a
       (labels ((next-page () (incf (page results)))
                (prev-page ()
                  (with-accessors ((current-page page)) results
                    (when (> current-page 0)
                      (decf current-page))))
                (print-results (results)
                  (format *terminal-io* "~&Query: ~a, Page: ~3d~%"
                          (query results)
                          (page results)))
                (get-results (results)
                  (with-accessors ((page page) (query query)) results
                    (parse-results results
                                   (run-query results))
                    (format-results (cases results))))
                (do-action (action results)
                  (funcall action)
                  (get-results results)))
 
e9a3dbce
         (loop
           (format *terminal-io* "~&Query? ")
           (finish-output *terminal-io*)
33870e9a
           (let ((action (or (query results)
                             (read-line *terminal-io*))))
e9a3dbce
             (string-case action
33870e9a
               ("quit" (return-from mainloop))
               ("help"
                (format *terminal-io* "~&Help:~%~:{~4t~a: ~a~%~}~%Anything else searches.~%"
                        `(("next" "Next page of results")
                          ("prev" "Previous page of results")
                          ("quit" "Quits"))))
 
e9a3dbce
               ("prev"
33870e9a
                (do-action #'prev-page results))
 
e9a3dbce
               ("next"
33870e9a
                (do-action #'next-page results))
 
               (t (setf (query results)
                        action)
                  (get-results results)))
             (setf (query results) nil))))
 
e9a3dbce
     (end-of-file (c) (declare (ignore c)))
     (sb-sys:interactive-interrupt (c) (declare (ignore c)))))