Add per-tag browsing on gopher - cl-yag - Common Lisp Yet Another website Gener… | |
git clone git://bitreich.org/cl-yag/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit 142b84ab78cb64423e2781a3e520bbd1e9cb40cd | |
parent 4a5228a3803cf285d220aedb5caa92b731375b62 | |
Author: Solene Rapenne <[email protected]> | |
Date: Fri, 12 Oct 2018 11:22:34 +0200 | |
Add per-tag browsing on gopher | |
Diffstat: | |
M Makefile | 2 +- | |
M data/articles.lisp | 4 ++-- | |
M generator.lisp | 143 +++++++++++++++++++----------… | |
M templates/gopher_head.tpl | 1 + | |
4 files changed, 93 insertions(+), 57 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -3,7 +3,7 @@ LISP= ecl | |
all: dirs html | |
html: $(HTML) css | |
- $(LISP) -load generator.lisp | |
+ $(LISP) --load generator.lisp | |
dirs: | |
mkdir -p "output/html/static" | |
diff --git a/data/articles.lisp b/data/articles.lisp | |
@@ -17,9 +17,9 @@ | |
:gopher-path "/user" ;; absolute path of yo… | |
:gopher-server "my.website" ;; hostname of the gop… | |
:gopher-port "70" ;; tcp port of the gop… | |
- :gopher-format "[0|~a|~a/article-~d.txt|~a|~a]~%~%" ;; menu format (geomyi… | |
+ :gopher-format "[~d|~a|~a|~a|~a]~%" ;; menu format (geomyi… | |
:gopher-index "index.gph" ;; menu file (geomyi… | |
- ;; :gopher-format "0~a ~a/article-~d.txt ~a ~a~%~%" ;;… | |
+ ;; :gopher-format "~d~a ~a ~a ~a~%" ;; menu format (… | |
;; :gopher-index "gophermap" ;; menu file (gopherni… | |
)) | |
diff --git a/generator.lisp b/generator.lisp | |
@@ -45,22 +45,22 @@ | |
(push (make-article :title title | |
:tag tag | |
:date (date-parse date) | |
- :rawdate date | |
+ :rawdate date | |
:tiny tiny | |
:author author | |
:id id | |
- :converter converter) | |
+ :converter converter) | |
*articles*)) | |
;; we add a converter to the list of the one availables | |
(defun converter(&optional &key name command extension) | |
(setf *converters* | |
- (append | |
- (list name | |
- (make-converter :name name | |
- :command command | |
- :extension extension)) | |
- *converters*))) | |
+ (append | |
+ (list name | |
+ (make-converter :name name | |
+ :command command | |
+ :extension extension)) | |
+ *converters*))) | |
;; load data from metadata and load config | |
(load "data/articles.lisp") | |
@@ -70,32 +70,32 @@ | |
;; common-lisp don't have a replace string function natively | |
(defun replace-all (string part replacement &key (test #'char=)) | |
(with-output-to-string (out) | |
- (loop with part-length = (length part) | |
- for old-pos = 0 then (+ pos part-length) | |
- for pos = (search part string | |
- :start2 old-pos | |
- :test test) | |
- do (write-string string out | |
- :start old-pos | |
- :end (or pos (length string))) | |
- when pos do (write-string replacement out) | |
- while pos))) | |
+ (loop with part-length = (length part) | |
+ for old-pos = 0 then (+ pos part-length) | |
+ for pos = (search part string | |
+ :start2 old-pos | |
+ :test test) | |
+ do (write-string string out | |
+ :start old-pos | |
+ :end (or pos (length string))) | |
+ when pos do (write-string replacement out) | |
+ while pos))) | |
;; common-lisp don't have a split string function natively | |
(defun split-str(text &optional (separator #\Space)) | |
"this function split a string with separator and return a list" | |
(let ((text (concatenate 'string text (string separator)))) | |
(loop for char across text | |
- counting char into count | |
- when (char= char separator) | |
- collect | |
- ;; we look at the position of the left separator from right to left | |
- (let ((left-separator-position (position separator text :from-end t … | |
- (subseq text | |
- ;; if we can't find a separator at the left of the current… | |
- ;; the string | |
- (if left-separator-position (+ 1 left-separator-position) … | |
- (- count 1)))))) | |
+ counting char into count | |
+ when (char= char separator) | |
+ collect | |
+ ;; we look at the position of the left separator from right to left | |
+ (let ((left-separator-position (position separator text :from-end t :… | |
+ (subseq text | |
+ ;; if we can't find a separator at the left of the current,… | |
+ ;; the string | |
+ (if left-separator-position (+ 1 left-separator-position) 0) | |
+ (- count 1)))))) | |
;; load a file as a string | |
;; we escape ~ to avoid failures with format | |
@@ -175,6 +175,30 @@ | |
`(progn | |
(save-file ,name (generate-layout ,@data)))) | |
+;; generate a gopher index file | |
+(defun generate-gopher-index(articles) | |
+ (let ((output (load-file "templates/gopher_head.tpl"))) | |
+ (dolist (article articles) | |
+ (setf output | |
+ (string | |
+ (concatenate 'string output | |
+ (format nil (getf *config* :gopher-format) | |
+ 0 ;;;; gopher type, 0 for text files | |
+ ;; here we create a 80 width char string wit… | |
+ ;; and date on the right | |
+ ;; we truncate the article title if it's too… | |
+ (let ((title (format nil "~80a" | |
+ (if (< 80 (length (arti… | |
+ (subseq (article-ti… | |
+ (article-title arti… | |
+ (replace title (article-rawdate article) :… | |
+ (concatenate 'string | |
+ (getf *config* :gopher-path) "/… | |
+ (getf *config* :gopher-server) | |
+ (getf *config* :gopher-port) | |
+ ))))) | |
+ output)) | |
+ | |
;; generate the list of tags | |
(defun articles-by-tag() | |
(let ((tag-list)) | |
@@ -243,7 +267,7 @@ | |
;; html generation of a tag homepage | |
(defun generate-tag-mainpage(articles-in-tag) | |
(apply #'concatenate 'string | |
- (loop for article in *articles* | |
+ (loop for article in *articles* | |
when (member (article-id article) articles-in-tag :test #'equal) | |
collect (create-article article :tiny t)))) | |
@@ -304,10 +328,10 @@ | |
;; produce index-titles.html where there are only articles titles | |
(generate "output/html/index-titles.html" (generate-semi-mainpage :no-text t… | |
- | |
+ | |
;; produce index file for each tag | |
(loop for tag in (articles-by-tag) do | |
- (generate (format nil "output/html/tag-~d.html" (getf tag :NAME)) | |
+ (generate (format nil "output/html/tag-~d.html" (getf tag :NAME)) | |
(generate-tag-mainpage (getf tag :VALUE)))) | |
;; generate rss gopher in html folder if gopher is t | |
@@ -325,29 +349,40 @@ | |
;; produce the gophermap file | |
(save-file (concatenate 'string "output/gopher/" (getf *config* :gopher-inde… | |
- (let ((output (load-file "templates/gopher_head.tpl"))) | |
- (dolist (article *articles*) | |
- (setf output | |
- (string | |
- (concatenate 'string output | |
- (format nil (getf *config* :gopher-format) | |
- ;; here we create a 80 width char… | |
- ;; and date on the right | |
- ;; we truncate the article title … | |
- (let ((title (format nil "~80a" | |
- (if (< 80 (l… | |
- (subseq … | |
- (article-t… | |
- (replace title (article-rawdate… | |
- | |
- | |
- (getf *config* :gopher-path) | |
- (article-id article) | |
- (getf *config* :gopher-server) | |
- (getf *config* :gopher-port) | |
- ))))) | |
- output)) | |
- | |
+ (generate-gopher-index *articles*)) | |
+ | |
+ ;; produce a tag list menu | |
+ (let* ((directory-path "output/gopher/_tags_/") | |
+ (index-path (concatenate 'string directory-path (getf *config* :gophe… | |
+ (ensure-directories-exist directory-path) | |
+ (save-file index-path | |
+ (let ((output (load-file "templates/gopher_head.tpl"))) | |
+ (loop for tag in (articles-by-tag) | |
+ do | |
+ (setf output | |
+ (string | |
+ (concatenate | |
+ 'string output | |
+ (format nil (getf *config* :gopher-format) | |
+ 1 ;; gopher type, 1 for menus | |
+ (getf tag :NAME) | |
+ (concatenate 'string | |
+ (getf *config* :gopher-path… | |
+ (getf *config* :gopher-server) | |
+ (getf *config* :gopher-port) | |
+ ))))) | |
+ output))) | |
+ | |
+ ;; produce each tag gophermap index | |
+ (loop for tag in (articles-by-tag) do | |
+ (let* ((directory-path (concatenate 'string "output/gopher/" (getf tag … | |
+ (index-path (concatenate 'string directory-path (getf *config* :… | |
+ (articles-with-tag (loop for article in *articles* | |
+ when (member (article-id article) (getf ta… | |
+ collect article))) | |
+ (ensure-directories-exist directory-path) | |
+ (save-file index-path (generate-gopher-index articles-with-tag)))) | |
+ | |
;; produce each article file (only a copy/paste in fact) | |
(loop for article in *articles* | |
do | |
diff --git a/templates/gopher_head.tpl b/templates/gopher_head.tpl | |
@@ -2,6 +2,7 @@ Hello, this is the head of your gophermap page, you can | |
customize it how you want ! | |
[0|RSS Feed|/~me/rss.xml|server|port] | |
+[1|Browse by tag|/~me/_tags_/|server|port] | |
----------------------------------------------------------------- | |