Skip to content

Instantly share code, notes, and snippets.

@indraniel
Last active June 11, 2022 20:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save indraniel/a595c5f0378cd914d4728c91b8cc568c to your computer and use it in GitHub Desktop.
Save indraniel/a595c5f0378cd914d4728c91b8cc568c to your computer and use it in GitHub Desktop.
A template to start a common-lisp project inside a separate "virtual environment"
.PHONY: init-project repl deps
#https://stackoverflow.com/a/23324703 (gets the absolute directory of the Makefile)
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
QUICKLISP_DIR := $(ROOT_DIR)/quicklisp
UTILS_DIR := $(QUICKLISP_DIR)/utils
SBCL := $(HOME)/sw/cl/sbcl/2.0.3/bin/sbcl
SWANK_HOST := "127.0.0.1"
SWANK_PORT := 4005
# SWANK SERVER CONTROL FILE ####################################################
define swank_server
;; install and initialize swank from quicklisp
(ql:quickload 'swank :verbose t)
(swank-loader:init :load-contribs t :setup t :delete t :quiet t)
;; add in a couple swank toggle on/off functions
(in-package :cl-user)
;; toggle on swank server
(defun start-swank (host port)
"Starts a Swank server thread, listening on PORT of the host's network
interface, to handle Swank Client connection requests."
(let ((swank::*loopback-interface* host))
(swank:create-server :port port :style :spawn :dont-close t)))
;; toggle off swank server
(defun stop-swank (port)
(format t "Stopping swank server~%")
(swank:stop-server port)
(format t ";; Swank off-line~%"))
endef
export swank_server
# CUSTOMIZED REPL PROMPT ######################################################
define repl_prompt
;; taken from: https://www.cliki.net/CMUCL%20Hints
(in-package :cl-user)
(defvar *last-package* nil)
(defvar *cached-prompt* nil)
(defun package-prompt (stream)
(unless (eq *last-package* *package*)
(setf *cached-prompt*
(concatenate 'string (or (first (package-nicknames *package*))
(package-name *package*))
"> "))
(setf *last-package* *package*))
(terpri)
(princ *cached-prompt* stream))
(setf sb-int:*repl-prompt-fun* #'package-prompt)
endef
export repl_prompt
init-project: $(QUICKLISP_DIR) $(UTILS_DIR)
echo $(ROOT_DIR)
$(SBCL) \
--no-sysinit \
--no-userinit \
--load $(QUICKLISP_DIR)/setup.lisp \
--eval '(ql:quickload :swank :verbose t)' \
--eval '(ql:quickload :swank-client :verbose t)' \
--eval '(ql:quickload :qlot :verbose t)' \
--eval '(quit)'
echo "$$swank_server" > $(UTILS_DIR)/swank-server.lisp
echo "$$repl_prompt" > $(UTILS_DIR)/repl-prompt.lisp
$(UTILS_DIR):
mkdir -p $(UTILS_DIR)
$(QUICKLISP_DIR): $(ROOT_DIR)/quicklisp.lisp
$(SBCL) \
--no-sysinit \
--no-userinit \
--load $(ROOT_DIR)/quicklisp.lisp \
--eval '(quicklisp-quickstart:install :path (merge-pathnames "quicklisp/" "$(ROOT_DIR)/"))' \
--eval '(quit)'
$(ROOT_DIR)/quicklisp.lisp:
curl -o $(ROOT_DIR)/quicklisp.lisp https://beta.quicklisp.org/quicklisp.lisp
repl:
@perl -le 'print q{vim/neovim invocation: nvim -c '\''let g:swank_host = $(SWANK_HOST)'\'' -c "let g:swank_port = $(SWANK_PORT)" foo.lisp}'
rlwrap $(SBCL) \
--no-sysinit \
--no-userinit \
--load $(QUICKLISP_DIR)/setup.lisp \
--load $(UTILS_DIR)/swank-server.lisp \
--load $(UTILS_DIR)/repl-prompt.lisp \
--eval '(start-swank $(SWANK_HOST) $(SWANK_PORT))'
# assuming you have neovim/vim and slimv installed
# nvim -c "let g:swank_host = '127.0.0.1'" -c "let g:swank_port = '4005'" baz.lisp
deps:
(ql:quickload :cl-project)
(defun hello (msg) (format t "Hi ~a !~%" msg))
(ql:quickload '("dexador" "plump" "lquery" "str"))
(ql:quickload :cl-json)
(ql:quickload :access)
(ql:quickload :arrow-macros)
(use-package :arrow-macros)
(defvar *url* "https://www.reddit.com/r/itookapicture.json")
(defvar *data* (dex:get *url*))
(defvar *parsed* (with-input-from-string (s *data*)
(cl-json:decode-json s)))
(assoc :title (rest (assoc :data (nth 0 (access:access (access:access *parsed* 'data) 'children)))))
(access:access (access:access (nth 0 (access:access (access:access *parsed* 'data) 'children)) 'data) 'title)
(-> *parsed*
(access:access 'data)
(access:access 'children)
(lambda (x) (nth 0 x))
(access:access 'data)
(access:access 'title))
(defun get-num-posts (data)
(->> data
(assoc :data)
(rest)
(assoc :children)
(rest)
(length)))
(defun get-title (data)
(->> data
(assoc :data)
(rest)
(assoc :children)
(rest)
(nth 0)
(assoc :data)
(rest)
(assoc :title)
(rest)))
(defun get-url (data)
(->> data
(assoc :data)
(rest)
(assoc :children)
(rest)
(nth 0)
(assoc :data)
(rest)
(assoc :url)
(rest)))
(with-input-from-string (s *data*)
(let* ((p (cl-json:decode-json s))
(title (get-title p))
(url (get-url p))
(num-posts (get-num-posts p)))
(format t "(~d) Title: ~a -- Url: ~a" num-posts title url)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment