first commit

This commit is contained in:
a. fox 2023-12-28 10:55:48 -05:00
commit 3a50b4288d
8 changed files with 160 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
bin/
*.fasl

16
Makefile Normal file
View File

@ -0,0 +1,16 @@
define LISP_CMDS
"(handler-case \
(progn (ql:quickload :lspx) \
(asdf:make :lspx)) \
(error (e) \
(format t \"~A~%\" e) \
(uiop:quit 1)))"
endef
.PHONY: clean all
all:
ros --eval $(LISP_CMDS)
clean:
rm -ri bin/

34
README.md Normal file
View File

@ -0,0 +1,34 @@
# lspx
### _a. fox_
a lisp take on [LuaX](https://bvisness.me/luax/)
## !! THIS SOFTWARE IS ALPHA QUALITY. USE AT YOUR OWN RISK
## Building
1. install [roswell](https://github.com/roswell/roswell)
2. `$ ros install sbcl-bin/2.3.11 && ros use sbcl-bin/2.3.11`
3. `$ git clone https://dev.focks.website/focks/lspx ~/common-lisp/lspx`
4. `$ cd ~/common-lisp/lspx && make`
## Using
`$ ./lspx -s ./my-site`
## Setup
After building the binary, you need to do a bit of work to setup your site.
The program expects all site files to live either in the specified directory (provided by `-s`) or the current directory if one isn't provided.
All pages are generated by compiling lisp files, then loading the compiled files. URLs are resolved by checking for files with names matching the URL slug (e.g., `my-site.com/toplevel/subpage` is loaded from `site-directory/pages/toplevel/subpage.lisp`)
Each page file should return a function that accepts no arguments and returns a string that should render the page.
## Tips and Tricks
;; TODO
## License
lol. lmao.

9
errors.lisp Normal file
View File

@ -0,0 +1,9 @@
;;;; errors.lisp
(in-package :lspx)
(defmacro http-error (code html)
`(defun ,(intern (format nil "~A-HANDLER" code)) ()
'(,code nil (,html))))
(http-error 404 "404 - page not found")

20
lspx.asd Normal file
View File

@ -0,0 +1,20 @@
;;;; lspx.asd
(asdf:defsystem #:lspx
:description "Describe lspx here"
:author "a. fox"
:license "Specify license here"
:version "0.0.1"
:serial t
:depends-on (#:clack #:unix-opts #:str #:hunchentoot)
:components ((:file "package")
(:file "opts")
(:file "errors")
(:file "lspx"))
:build-operation "program-op"
:build-pathname "bin/lspx"
:entry-point "lspx::main")
#+sb-core-compression
(defmethod asdf:perform ((o asdf:image-op) (c asdf:system))
(uiop:dump-image (asdf:output-file o c) :executable t :compression t))

51
lspx.lisp Normal file
View File

@ -0,0 +1,51 @@
;;;; lspx.lisp
(in-package #:lspx)
(defparameter *server* nil)
(defun web-handler (env)
"handle the request by searching for a lisp file that matches the path provided in the url
if we find the file we compile it using block compilation and load the fasl
if we cannot find the file we throw an error"
(destructuring-bind (&key path-info &allow-other-keys) env
(let* ((logical-path (str:replace-all "/" ";" path-info))
(path (if (string= logical-path ";")
";index" logical-path))
(filepath (str:concat "web:pages;" path ".lisp"))
(faslpath (str:replace-all "lisp" "fasl" filepath)))
(if (uiop:file-exists-p filepath)
(progn
(unless (uiop:file-exists-p faslpath)
(compile-file filepath
:block-compile t :entry-points nil
:output-file faslpath))
`(200 nil ,(funcall (load faslpath))))
(404-handler)))))
(defun main ()
(multiple-value-bind (opts args) (get-opts)
;; --help
(when (getf opts :help)
(opts:describe :usage-of "lspx")
(uiop:quit 0))
;; handles -d/--dir
(setf (logical-pathname-translations "WEB")
`(("WEB:*;**;*.*.*"
,(if (getf opts :site)
(format nil "~A~:[/~;~]*/**/*.*"
(getf opts :site)
(uiop:string-suffix-p (getf opts :site) "/"))
"./*/**/*.*"))))
;; handles -p/--port
(setf *server*
(clack:clackup #'web-handler
:port (getf opts :port 5000)))
;;
;; todo: block here while we handle our http requests
;;
))

21
opts.lisp Normal file
View File

@ -0,0 +1,21 @@
;;;; opts.lisp
(in-package :lspx)
(define-opts
(:name :help
:description "prints this help"
:short #\h
:long "help")
(:name :site
:description "specify the path where the site files live. defaults to current directory"
:short #\s
:long "site"
:arg-parser #'identity
:meta-var "DIRECTORY")
(:name :port
:description "port to use for server. defaults to 5000"
:short #\p
:long "port"
:arg-parser #'parse-integer
:meta-var "PORT"))

7
package.lisp Normal file
View File

@ -0,0 +1,7 @@
;;;; package.lisp
(defpackage #:lspx
(:use #:cl)
(:import-from :unix-opts
:define-opts
:get-opts))