From 142b84ab78cb64423e2781a3e520bbd1e9cb40cd Mon Sep 17 00:00:00 2001 From: Solene Rapenne Date: Fri, 12 Oct 2018 11:22:34 +0200 Subject: [PATCH] Add per-tag browsing on gopher --- Makefile | 2 +- data/articles.lisp | 4 +- generator.lisp | 143 ++++++++++++++++++++++++-------------- templates/gopher_head.tpl | 1 + 4 files changed, 93 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index ea064e9..cf8981e 100644 --- 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 index d64bff6..35b10f6 100644 --- a/data/articles.lisp +++ b/data/articles.lisp @@ -17,9 +17,9 @@ :gopher-path "/user" ;; absolute path of your gopher directory :gopher-server "my.website" ;; hostname of the gopher server :gopher-port "70" ;; tcp port of the gopher server, 70 usually - :gopher-format "[0|~a|~a/article-~d.txt|~a|~a]~%~%" ;; menu format (geomyidae) + :gopher-format "[~d|~a|~a|~a|~a]~%" ;; menu format (geomyidae) :gopher-index "index.gph" ;; menu file (geomyidae) - ;; :gopher-format "0~a ~a/article-~d.txt ~a ~a~%~%" ;; menu format (gophernicus and others) + ;; :gopher-format "~d~a ~a ~a ~a~%" ;; menu format (gophernicus and others) ;; :gopher-index "gophermap" ;; menu file (gophernicus and others) )) diff --git a/generator.lisp b/generator.lisp index 1d40b9f..27653d1 100644 --- 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 :end (- count 1)))) - (subseq text - ;; if we can't find a separator at the left of the current, then it's the start of - ;; the string - (if left-separator-position (+ 1 left-separator-position) 0) - (- 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 :end (- count 1)))) + (subseq text + ;; if we can't find a separator at the left of the current, then it's the start of + ;; 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 with title on the left + ;; and date on the right + ;; we truncate the article title if it's too large + (let ((title (format nil "~80a" + (if (< 80 (length (article-title article))) + (subseq (article-title article) 0 80) + (article-title article))))) + (replace title (article-rawdate article) :start1 (- (length title) (length (article-rawdate article))))) + (concatenate 'string + (getf *config* :gopher-path) "/article-" (article-id article) ".txt") + (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-index)) - (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 string with title on the left - ;; and date on the right - ;; we truncate the article title if it's too large - (let ((title (format nil "~80a" - (if (< 80 (length (article-title article))) - (subseq (article-title article) 0 80) - (article-title article))))) - (replace title (article-rawdate article) :start1 (- (length title) (length (article-rawdate article))))) - - - (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* :gopher-index)))) + (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 tag :NAME) "/") + (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 :NAME) "/")) + (index-path (concatenate 'string directory-path (getf *config* :gopher-index))) + (articles-with-tag (loop for article in *articles* + when (member (article-id article) (getf tag :VALUE) :test #'equal) + 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 index e93171e..d4b1248 100644 --- 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] -----------------------------------------------------------------