aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build-app.lisp58
-rw-r--r--clpmfile.lock23
-rw-r--r--oneliners.cli.asd1
-rw-r--r--src/lib.lisp115
4 files changed, 120 insertions, 77 deletions
diff --git a/build-app.lisp b/build-app.lisp
index c7f8667..1b16837 100644
--- a/build-app.lisp
+++ b/build-app.lisp
@@ -1,14 +1,26 @@
+;;; build-app.lisp -- Contains the command line frontend definition
+;;; to build the cli, simply load this file from the command line.
+
(asdf:load-system "oneliners.cli")
(defpackage #:oneliners.cli.app
(:use #:cl #:net.didierverna.clon)
- (:local-nicknames (#:a #:alexandria)))
+ (:local-nicknames (#:a #:alexandria)
+ (#:cli #:oneliners.cli)))
(in-package :oneliners.cli.app)
-(defsynopsis (:postfix "TERMS ... | N ARGS ...")
- (text :contents "Search for oneliner mentioning TERMS or run the Nth search result with arguments ARGS.")
+;;; HELP TEXTS
+(defparameter +invite-help-text+
+ "")
+
+
+;;; CLON SYNOPSIS DEFINITION
+
+(defsynopsis (:postfix "[TERMS ...] | N [ARGS ...]")
(group (:header "Search")
+ (text :contents "Usage: ol [OPTIONS] [TERMS ...]")
+ (text :contents "Each term may be a command name or some tag like 'server' or 'tunnel'")
(lispobj :long-name "count"
:argument-type :optional
:argument-name "Count"
@@ -17,8 +29,22 @@
:typespec 'integer)
(flag :long-name "not-flagged"
:description "Request that no flagged oneliners are returned."))
+ (text :contents " ")
+ (group (:header "Running Oneliners")
+ (text :contents "Usage: ol [OPTIONS] N [ARGS ...]")
+ (text :contents "Runs the Nth search result with possible arguments ARGS.")
+ (flag :long-name "clip"
+ :description "Force an attempt to copy the oneliner to the clipboard instead of running it."))
+ (text :contents " ")
+ (group (:header "Help")
+ (flag :long-name "help"
+ :description "Print this help menu.")
+ (enum :long-name "help-topic"
+ :enum '(:admin :wiki :invites)
+ :argument-name "TOPIC"
+ :description "Print help for a topic. Topics are: wiki, admin, invites"))
(group (:header "Wiki" :hidden t)
- (text :contents "This is text")
+ (text :contents "This section documents options used to add and edit oneliners in the wiki.")
(flag :long-name "add-interactive"
:description "Interactively add a new oneliner")
(flag :long-name "update-interactive"
@@ -30,25 +56,26 @@
:argument-type :optional
:default-value "DUMMY-TOKEN"
:argument-name "TOKEN"
- :description "Redeem an invite token. Enter an
- interactive process of setting up a new contributor
- account with the inviting server"))
- (group (:header "Help")
- (flag :long-name "help"
- :description "Print this help menu.")
- (enum :long-name "help-topic"
- :enum '(:admin :wiki :search :help)
- :argument-name "TOPIC"
- :description "Print help for a topic. Topics are: search, wiki, admin, help")))
+ :description "Redeem an invite token. See also --help-topic=invites"))
+ (group (:header "Invites" :hidden t)
+ (text :contents +invite-help-text+)))
+;;; HELPERS
+
(defun find-group-with-header (header)
+ "This function should be built in. Is it? How to know? The
+documentation is both extensive and trash. Any manual that expects
+you to go to sleep with it at night is written for the author more
+than the users."
(loop for item in (net.didierverna.clon::items *synopsis*)
when (and (typep item 'net.didierverna.clon::group)
(string-equal header (net.didierverna.clon::header item)))
return item))
+;;; MAIN ENTRY POINT
+
(defun main ()
"Entry point for our standalone application."
(make-context)
@@ -71,9 +98,10 @@
hist-number (rest arguments))
(uiop:quit))
- (format t "TBD: Going to search for commands mentioning the terms ~a~%" arguments))
+ (cli:search-for-oneliners arguments :))
(uiop:quit))
+;;; DUMP EXECUTABLE
(dump "ol" main)
diff --git a/clpmfile.lock b/clpmfile.lock
index 53f4c43..c694db9 100644
--- a/clpmfile.lock
+++ b/clpmfile.lock
@@ -43,11 +43,16 @@
("chunga" :version "2020-04-27" :source "quicklisp" :systems ("chunga"))
("cl+ssl" :version "2021-12-30" :source "quicklisp" :systems ("cl+ssl"))
("cl-base64" :version "2020-10-16" :source "quicklisp" :systems ("cl-base64"))
+("cl-change-case" :version "2021-04-11" :source "quicklisp" :systems
+ ("cl-change-case"))
("cl-clon" :version "2021-04-11" :source "quicklisp" :systems
("net.didierverna.clon" "net.didierverna.clon.core"
"net.didierverna.clon.setup" "net.didierverna.clon.setup/termio"))
("cl-cookie" :version "2019-10-07" :source "quicklisp" :systems ("cl-cookie"))
-("cl-ppcre" :version "2019-05-21" :source "quicklisp" :systems ("cl-ppcre"))
+("cl-ppcre" :version "2019-05-21" :source "quicklisp" :systems
+ ("cl-ppcre" "cl-ppcre-unicode"))
+("cl-str" :version "2021-05-31" :source "quicklisp" :systems ("str"))
+("cl-unicode" :version "2021-02-28" :source "quicklisp" :systems ("cl-unicode"))
("cl-utilities" :version "2010-10-07" :source "quicklisp" :systems
("cl-utilities"))
("dexador" :version "2021-12-09" :source "quicklisp" :systems ("dexador"))
@@ -134,6 +139,8 @@
("cl-base64" ((:system :name "dexador") (:system :name "cl-base64")))
+("cl-change-case" ((:system :name "str") (:system :name "cl-change-case")))
+
("cl-clon"
((:system :name "oneliners.cli") (:system :name "net.didierverna.clon"))
((:system :name "net.didierverna.clon.termio")
@@ -153,8 +160,18 @@
("cl-cookie" ((:system :name "dexador") (:system :name "cl-cookie")))
-("cl-ppcre" ((:system :name "dexador") (:system :name "cl-ppcre"))
- ((:system :name "cl-cookie") (:system :name "cl-ppcre")))
+("cl-ppcre" ((:system :name "str") (:system :name "cl-ppcre"))
+ ((:system :name "str") (:system :name "cl-ppcre-unicode"))
+ ((:system :name "dexador") (:system :name "cl-ppcre"))
+ ((:system :name "cl-unicode") (:system :name "cl-ppcre"))
+ ((:system :name "cl-ppcre-unicode") (:system :name "cl-ppcre"))
+ ((:system :name "cl-cookie") (:system :name "cl-ppcre"))
+ ((:system :name "cl-change-case") (:system :name "cl-ppcre"))
+ ((:system :name "cl-change-case") (:system :name "cl-ppcre-unicode")))
+
+("cl-str" ((:system :name "oneliners.cli") (:system :name "str")))
+
+("cl-unicode" ((:system :name "cl-ppcre-unicode") (:system :name "cl-unicode")))
("cl-utilities" ((:system :name "quri") (:system :name "cl-utilities"))
((:system :name "fast-http") (:system :name "cl-utilities")))
diff --git a/oneliners.cli.asd b/oneliners.cli.asd
index 10e8f39..45d5d5b 100644
--- a/oneliners.cli.asd
+++ b/oneliners.cli.asd
@@ -3,6 +3,7 @@
:author "Colin Okay"
:license "AGPLv3"
:depends-on ("trivial-clipboard"
+ "str"
"dexador"
"osicat"
"net.didierverna.clon"
diff --git a/src/lib.lisp b/src/lib.lisp
index 20f75ea..2480dab 100644
--- a/src/lib.lisp
+++ b/src/lib.lisp
@@ -3,62 +3,71 @@
(defpackage oneliners.cli
(:use :cl)
(:local-nicknames (#:api #:oneliners.api-client)))
-(in-package :oneliners.cli)
-;;; CLI OPTIONS
-
-;; (opts:define-opts
-;; (:name :add
-;; :description "Intaractively add a oneliner to the a wiki."
-;; :long "add")
-;; (:name :tags
-;; :description "A comma separated list of tags to filter search results."
-;; :short #\t
-;; :long "tags"
-;; :arg-parser #'identity
-;; :meta-var "'T1, T2, ...'")
-;; (:name :limit
-;; :description "An integer. The maximum number of results to return."
-;; :short #\l
-;; :long "limit"
-;; :meta-var "N"
-;; :default 10
-;; :arg-parser #'parse-integer)
-;; (:name :edit
-;; :description "An integer, a result number. Interactively edit af command."
-;; :long "edit"
-;; :meta-var "RESULT"
-;; :arg-parser #'parse-integer)
-;; (:name :not-flagged
-;; :description "Filter flagged oneliners from the search results"
-;; :long "not-flagged"))
-
-(defparameter +help-suffix+
- "Unless RESULT is an integer, search for oneliners that involve each command in COMMANDS.
-E.g.
- # search for oneliners involving both 'find' and 'grep'
- ol find grep
-
-Otherwise, when RESULT is an integer, run the oneliner with index RESULT from the most
-recent search command, and supply ARGS to that oneliner, if provided.
-E.g.
- # run the third result from the last search with arguments foo and bar
- ol 3 foo bar")
-
-;; (defun help-text ()
-;; (opts:describe :prefix "Oneliners Wiki Command Line Tool"
-;; :args "[[RESULT ARGS | COMMANDS]"
-;; :usage-of "ol"
-;; :suffix +help-suffix+))
+(in-package :oneliners.cli)
;;; CONFIG AND RESULTS FILE LOCATIONS
+(defvar *config* nil
+ "A configuration plist")
+
+(defun make-config (&key host api-token)
+ (append (when host (list :host host))
+ (when api-token (list :api-token api-token))))
+
+(defun valid-config-p (config)
+ (and (listp config)
+ (evenp (length config))
+ (stringp (getf config :host))
+ t))
+
+(defun write-default-config-to-disk ()
+ (let ((conf-file (config-file)))
+ (ensure-directories-exist conf-file)
+ (with-open-file (out conf-file :direction :output)
+ (print (make-config :host "https://oneliners.wiki") out))))
+
+(defun fetch-config-from-disk ()
+ (let ((conf
+ (uiop:with-safe-io-syntax ()
+ (uiop:read-file-form (config-file)))))
+ (assert (valid-config-p conf) () "Invalid configuration file")
+ (setf *config* conf)))
+
+(defun ensure-config ()
+ (unless (uiop:file-exists-p (config-file))
+ (write-default-config-to-disk))
+ (fetch-config-from-disk))
+
+(defun host () (getf *config* :host))
+(defun api-token () (getf *config* :api-token))
+
(defun config-file ()
- (merge-pathnames ".config/oneliners.config" (user-homedir-pathname) ))
+ (merge-pathnames ".config/oneliners.config" (user-homedir-pathname)))
(defun last-search-file ()
(merge-pathnames ".last_oneliners_search" (user-homedir-pathname)))
+(defun fetch-nth-oneliner (n)
+ "Returns nil if there is no nth oneliner from the search history."
+ (when (uiop:file-exists-p (last-search-file))
+ (nth n (uiop:read-file-form (last-search-file)))))
+
+;;; SEARCHNG THE WIKI
+
+(defun search-for-oneliners (terms limit not-flagged-p)
+ (assert (loop for term in terms never (find #\, term) ))
+ (handler-case
+ (api:request-with
+ (:host (host))
+ (api:get--search :tags (str:join ",")
+ :limit limit
+ :notflagged (if not-flagged-p "true" "false")))
+ (dex:http-request-failed (e)
+ (format *error-output* "~a -- ~a"
+ (dex:response-status e)
+ (dex:response-body e)))))
+
;;; RUNNING COMMANDS
(defun parent-process-name ()
@@ -103,15 +112,3 @@ printed to OUTPUT-STREAM. "
do (princ (read-line shell-output) output-stream)
(terpri output-stream))))))
-;;; main
-
-;; (defun main ()
-;; (handler-case
-;; (multiple-value-bind (options free-args) (opts:get-opts)
-;; (print (list :options options :free-args free-args))
-;; (terpri)
-;; (uiop:quit))
-;; (unix-opts:unknown-option (err)
-;; (declare (ignore err))
-;; (princ (help-text))
-;; (terpri))))