From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH] reader: Add Gemtext reader. Resent-From: Arun Isaac Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Mon, 04 Apr 2022 09:29:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: 54705@debbugs.gnu.org Cc: Arun Isaac X-Debbugs-Original-To: skribilo-bugs@nongnu.org Received: via spool by submit@debbugs.gnu.org id=B.164906448932638 (code B ref -1); Mon, 04 Apr 2022 09:29:01 +0000 Received: (at submit) by debbugs.gnu.org; 4 Apr 2022 09:28:09 +0000 Received: from localhost ([127.0.0.1]:50507 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nbJ0K-0008UK-9u for submit@debbugs.gnu.org; Mon, 04 Apr 2022 05:28:09 -0400 Received: from lists.gnu.org ([209.51.188.17]:45586) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nbJ0H-0008UB-Kn for submit@debbugs.gnu.org; Mon, 04 Apr 2022 05:28:06 -0400 Received: from eggs.gnu.org ([209.51.188.92]:58392) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nbJ0H-0002w5-5K for skribilo-bugs@nongnu.org; Mon, 04 Apr 2022 05:28:05 -0400 Received: from mugam.systemreboot.net ([139.59.75.54]:55548) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nbJ0A-00083b-LN for skribilo-bugs@nongnu.org; Mon, 04 Apr 2022 05:28:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=systemreboot.net; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=cVWc6jhW9XrPEgHYJg9wKKNZs9WeoWtKEIQb4t2SkHY=; b=EOl6+mSXLGkwFXJQoP85zkTyDy PfXh0y1fIVSQ+nO5VR3uIfbKDDGmW970JV5WAY4NkTYiFpHENZ87nCLV7s8xf3PaXgkkLRyCPgJ0C 9JrZSnFf1QUo6AygHEEYO6MEJd8T2RkRd5WKR5A4v4PpvrqCIibLVGP0x0dG/2uvPhunmhy2+EFDW f25/QqAXguv4lhHBHMkP6YAghvpNSw/7n7mp+dlMWzTR7qtcV0EdVS7KKpLimu3dhJyRvBXeMTAJH EbTuSryB6FtK4/3TaBry2VpHfbdOEH1gzPFUV6JOJsu+2GronuLCP99a5oumQr1naIWuU/T3P2X9g nDB1WxjA==; Received: from [192.168.2.1] (port=58192 helo=localhost.localdomain) by systemreboot.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nbJ02-000g5P-DZ; Mon, 04 Apr 2022 14:57:50 +0530 From: Arun Isaac Date: Mon, 4 Apr 2022 14:57:42 +0530 Message-Id: <20220404092742.11963-1-arunisaac@systemreboot.net> X-Mailer: git-send-email 2.34.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=139.59.75.54; envelope-from=arunisaac@systemreboot.net; helo=mugam.systemreboot.net X-Spam_score_int: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, PDS_OTHER_BAD_TLD=1.997, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Score: 0.2 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) * src/guile/skribilo/reader/gemtext.scm: New file. * src/guile/Makefile.am (readers): Register it. * doc/user/syntax.skb (The Gemtext Syntax): New section. * tests/readers/gemtext.test: New file. * tests/Makefile.am (TESTS): Add readers/gemtext.test. --- doc/user/syntax.skb | 21 ++- src/guile/Makefile.am | 3 +- src/guile/skribilo/reader/gemtext.scm | 231 ++++++++++++++++++++++++++ tests/Makefile.am | 3 +- tests/readers/gemtext.test | 133 +++++++++++++++ 5 files changed, 388 insertions(+), 3 deletions(-) create mode 100644 src/guile/skribilo/reader/gemtext.scm create mode 100644 tests/readers/gemtext.test diff --git a/doc/user/syntax.skb b/doc/user/syntax.skb index 9a4070c..2de7cbd 100644 --- a/doc/user/syntax.skb +++ b/doc/user/syntax.skb @@ -211,7 +211,26 @@ documents that can be output in variety of formats (see ,(numref :text [Chapter] :ident "engines")). The downside is that, being a very simple markup-less document format, there are many things that cannot be done using it, most notably tables, bibliographies, and cross-references.])) - + + (section :title [The Gemtext Syntax] :ident "gemtext-syntax" + (p [,(ref +:url "https://gemini.circumlunar.space/docs/gemtext.gmi" +:text "Gemtext"), the lightweight markup language used by the ,(ref +:url "https://gemini.circumlunar.space" :text "Gemini protocol"), is +supported as an input syntax. To use it, just pass ,(tt +[--reader=gemtext]) to the compiler. When used programmatically, the +Gemtext reader can be customized using the following options.]) + + (doc-markup 'make-gemtext-reader + '((:join-lines? [If ,(code "#t"), lines which are not +separated by a blank line are joined into a single paragraph. This is +a relaxation of the Gemtext standard, and is not done by default.]) + (:section-numbers? [If ,(code "#t"), sections are +numbered. Else, they are not.])) + :common-args '() + :source "skribilo/reader/gemtext.scm" + :idx *function-index*)) + (section :title [The RSS 2.0 Syntax] :ident "rss2-syntax" diff --git a/src/guile/Makefile.am b/src/guile/Makefile.am index 98f2873..0a66a88 100644 --- a/src/guile/Makefile.am +++ b/src/guile/Makefile.am @@ -47,7 +47,8 @@ SOURCES = \ SOURCES += $(readers) $(packages) $(engines) readers = \ - skribilo/reader/skribe.scm skribilo/reader/outline.scm + skribilo/reader/skribe.scm skribilo/reader/outline.scm \ + skribilo/reader/gemtext.scm if BUILD_RSS2_READER diff --git a/src/guile/skribilo/reader/gemtext.scm b/src/guile/skribilo/reader/gemtext.scm new file mode 100644 index 0000000..4ae403c --- /dev/null +++ b/src/guile/skribilo/reader/gemtext.scm @@ -0,0 +1,231 @@ +;;; gemtext.scm -- A reader for the Gemini protocol's Gemtext markup +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (skribilo reader gemtext) + #:use-module (rnrs io ports) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) + #:use-module (srfi srfi-171) + #:use-module (ice-9 match) + #:use-module ((ice-9 textual-ports) #:select (unget-char unget-string)) + #:use-module (skribilo reader) + #:use-module (skribilo utils syntax) + #:export (reader-specification + make-gemtext-reader)) + +(skribilo-module-syntax) + +;;; Author: Arun Isaac +;;; +;;; Commentary: +;;; +;;; A reader for gemtext, the lightweight markup language used by the +;;; Gemini protocol +;;; +;;; Code: + +(define %join-lines? + (make-parameter #f)) + +(define %section-numbers? + (make-parameter #f)) + +(define (string-blank? str) + "Return #t if STR contains only whitespace characters. Else, return +#f." + (string-every char-set:whitespace str)) + +(define (string-remove-prefix prefix str) + "Return STR with PREFIX removed. If PREFIX is not a prefix of STR, +return #f." + (and (string-prefix? prefix str) + (substring str (string-length prefix)))) + +(define (string-partition str char-pred) + "Return the part of STR before and after the first occurrence of +CHAR-PRED as two values." + (let ((partition-index (string-index str char-pred))) + (if partition-index + (values (substring str 0 partition-index) + (substring str partition-index)) + (values str #f)))) + +(define (unget-line port line) + "Place the string LINE in PORT so that subsequent read operations +will read LINE followed by a newline character." + (unget-char port #\newline) + (unget-string port line)) + +(define (read-preformatted-text in out) + "Read preformatted text from port IN and write it to port OUT." + (let ((line (get-line in))) + (unless (or (eof-object? line) + (string-prefix? "```" line)) + (put-string out line) + (newline out) + (read-preformatted-text in out)))) + +(define (heading-level line) + "Return the level of the heading in LINE. If LINE is not a heading, +return #f." + (cond + ((string-prefix? "### " line) 3) + ((string-prefix? "## " line) 2) + ((string-prefix? "# " line) 1) + (else #f))) + +(define (read-section-children level port) + "Read section elements of LEVEL from PORT. Return as a list." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) (list)) + ;; If another heading of same or higher level begins, unget line + ;; and end section. + ((let ((heading-level (heading-level line))) + (and heading-level + (<= heading-level level))) + (unget-line port line) + (list)) + ;; If blank line, continue. + ((string-blank? line) + (read-section-children level port)) + ;; Else, add element and continue. + (else + (unget-line port line) + (cons (read-gemtext-element port) + (read-section-children level port)))))) + +(define (paragraph-line? line) + "Return #t if LINE is a paragraph line. Else, return #f." + (not (or (string-blank? line) + (heading-level line) + (string-prefix? "* " line) + (string-prefix? ">" line) + (string-prefix? "=>" line) + (string-prefix? "```" line)))) + +(define (link-line->ref line) + "Convert link LINE to a skribilo ref expression." + (let* ((trimmed-line (string-trim (string-remove-prefix "=>" line))) + (url text (string-partition trimmed-line (char-set #\space #\tab)))) + (if text + `(ref #:url ,url #:text ,(string-trim text)) + `(ref #:url ,url)))) + +(define (retf-unget-line port result line) + "Unget LINE to PORT and return RESULT. This function is used as an +argument to ttake-while." + (unget-line port line) + result) + +(define (read-gemtext-element port) + "Read next gemtext element from PORT." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) line) + ;; Section + ((heading-level line) + => (lambda (level) + `(,(case level + ((1) 'section) + ((2) 'subsection) + ((3) 'subsubsection)) + #:title ,(substring line (1+ level)) + #:number ,(%section-numbers?) + ,@(read-section-children level port)))) + ;; List + ((string-remove-prefix "* " line) + => (lambda (first-item) + `(itemize + ,@(port-transduce (compose (ttake-while (cut string-prefix? "* " <>) + (cut retf-unget-line port <> <>)) + (tmap (lambda (line) + `(item ,(string-remove-prefix "* " line))))) + rcons + (list `(item ,first-item)) + get-line + port)))) + ;; Blockquote + ((string-remove-prefix ">" line) + => (lambda (first-line) + (list 'blockquote + (if (%join-lines?) + (string-join + (port-transduce (compose (ttake-while (cut string-prefix? ">" <>) + (cut retf-unget-line port <> <>)) + (tmap (cut string-remove-prefix ">" <>))) + rcons + (list first-line) + get-line + port) + " ") + line)))) + ;; Link + ((string-prefix? "=>" line) + (cons 'paragraph + (port-transduce (compose (ttake-while (cut string-prefix? "=>" <>) + (cut retf-unget-line port <> <>)) + (tmap link-line->ref)) + rcons + (list (link-line->ref line)) + get-line + port))) + ;; Preformatted text + ((string-remove-prefix "```" line) + => (lambda (alt-text) + ;; We don't use the alt text. + `(pre ,(call-with-output-string + (cut read-preformatted-text port <>))))) + ;; Ignore blank lines. + ((string-blank? line) (read-gemtext-element port)) + ;; Paragraph + (else + (list 'paragraph + (if (%join-lines?) + (string-join + (port-transduce (ttake-while paragraph-line? + (cut retf-unget-line port <> <>)) + rcons + (list line) + get-line + port) + " ") + line)))))) + +(define* (make-gemtext-reader :key join-lines? section-numbers?) + "Return a gemtext reader. + +If JOIN-LINES? is #t, lines which are not separated by a blank line +are joined into a single paragraph. + +If SECTION-NUMBERS? is #t, sections are numbered. Else, they are not." + (lambda (port) + (parameterize ((%join-lines? join-lines?) + (%section-numbers? section-numbers?)) + (match (port-transduce (tmap identity) + rcons + read-gemtext-element + port) + (() (eof-object)) + (elements `(document ,@elements)))))) + +(define-reader gemtext "0.1" make-gemtext-reader) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8ba7637..16478a9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -13,7 +13,8 @@ TESTS = \ ast.test \ resolve.test \ engines/info.test \ - location.test + location.test \ + readers/gemtext.test if BUILD_RSS2_READER diff --git a/tests/readers/gemtext.test b/tests/readers/gemtext.test new file mode 100644 index 0000000..99891c8 --- /dev/null +++ b/tests/readers/gemtext.test @@ -0,0 +1,133 @@ +;;; Exercise Gemtext reader. -*- Scheme -*- +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (tests gemtext) + #:use-module (srfi srfi-64) + #:use-module (ice-9 match) + #:use-module (skribilo reader)) + +(define make-gemtext-reader + (reader:make (lookup-reader 'gemtext))) + +(define-syntax-rule (match? exp pattern) + (match exp + (pattern #t) + (_ #f))) + + + +(test-begin "gemtext") + +(test-assert "basic gemtext document" + (match? (call-with-input-string "# Heading +* Mercury +* Gemini +* Apollo +## Subheading + +### Subsubheading + +> I contend that text-based websites should not exceed in size the major works of Russian literature. + +# Links + +=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com + +``` +This is a preformatted block. +``` + +```alt +This is a preformatted block with \"alt text\". +```" + (make-gemtext-reader)) + `(document + (section #:title "Heading" #:number #f + (itemize (item "Mercury") + (item "Gemini") + (item "Apollo")) + (subsection #:title "Subheading" #:number #f + (subsubsection #:title "Subsubheading" #:number #f + (blockquote "> I contend that text-based websites should not exceed in size the major works of Russian literature.")))) + (section #:title "Links" #:number #f + (paragraph (ref #:url "https://example.com" #:text "A cool website") + (ref #:url "gopher://example.com" #:text "An even cooler gopherhole") + (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule") + (ref #:url "sftp://example.com")) + (pre "This is a preformatted block.\n") + (pre "This is a preformatted block with \"alt text\".\n"))))) + +(test-assert "do not join short lines into paragraph" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-assert "join short lines into paragraphs" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader #:join-lines? #t)) + `(document + (paragraph "Foo Bar")))) + +(test-assert "do not number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader)) + `(document + (section #:title "Foo" #:number #f + (subsection #:title "Bar" #:number #f))))) + +(test-assert "number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader #:section-numbers? #t)) + `(document + (section #:title "Foo" #:number #t + (subsection #:title "Bar" #:number #t))))) + +(test-assert "break up links separated by blank lines into paragraphs" + (match? (call-with-input-string "=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole + +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com" + (make-gemtext-reader)) + `(document + (paragraph (ref #:url "https://example.com" #:text "A cool website") + (ref #:url "gopher://example.com" #:text "An even cooler gopherhole")) + (paragraph (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule") + (ref #:url "sftp://example.com"))))) + +(test-assert "ignore blank lines that have a non-zero number of whitespace characters" + (match? (call-with-input-string "Foo + +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-end "gemtext") -- 2.34.0 From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH] reader: Add Gemtext reader. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Sun, 10 Apr 2022 20:12:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: Arun Isaac Cc: 54705@debbugs.gnu.org Received: via spool by 54705-submit@debbugs.gnu.org id=B54705.16496215065207 (code B ref 54705); Sun, 10 Apr 2022 20:12:01 +0000 Received: (at 54705) by debbugs.gnu.org; 10 Apr 2022 20:11:46 +0000 Received: from localhost ([127.0.0.1]:41620 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ndduS-0001Lt-GX for submit@debbugs.gnu.org; Sun, 10 Apr 2022 16:11:46 -0400 Received: from eggs.gnu.org ([209.51.188.92]:46562) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ndduM-0001Lb-Uz for 54705@debbugs.gnu.org; Sun, 10 Apr 2022 16:11:42 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:48428) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ndduG-0008Ec-EV; Sun, 10 Apr 2022 16:11:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:In-Reply-To:Date:References:Subject:To: From; bh=kNRmFgSeUqzxhfGYZUPs+u5kqt7LLXGzpJgx1IZNlZw=; b=lsYE/SUabPtpsxYZqi3b 87K5FLIo+0lk558vCMtqd4aLSjtvP4NfyAPq0aEkk9L7QGpjSD8L1rqeAgsOVawxrMmPjnYfg2JwL ubM7Eww246M6uwo2KMN0l0tKcQpGTmO6eJCXWXuYyCi0puw6H41f9k8heqW2Y2oA9sUEyEa8a2HNg X+lUBFpozTvJ8hm5Uob4hniJ3LNsSfmfovCO7cKtznVbwo0iQcTL6PsAAGBUQQVs8i3v3Fr4znD7k J1tlgtQOwx5e5XTXChriK1cZyXDPOtwcRcWyZ6BXOk8z5I9/i8EfoCIIi4Ml4k3TdLphGqkMDzA1j U5N8B0+Mry1leg==; Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:54855 helo=ribbon) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ndduF-0005v5-8a; Sun, 10 Apr 2022 16:11:32 -0400 From: Ludovic =?UTF-8?Q?Court=C3=A8s?= References: <20220404092742.11963-1-arunisaac@systemreboot.net> Date: Sun, 10 Apr 2022 22:11:29 +0200 In-Reply-To: <20220404092742.11963-1-arunisaac@systemreboot.net> (Arun Isaac's message of "Mon, 4 Apr 2022 14:57:42 +0530") Message-ID: <87a6cs66mm.fsf@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hey! Arun Isaac skribis: > * src/guile/skribilo/reader/gemtext.scm: New file. > * src/guile/Makefile.am (readers): Register it. > * doc/user/syntax.skb (The Gemtext Syntax): New section. > * tests/readers/gemtext.test: New file. > * tests/Makefile.am (TESTS): Add readers/gemtext.test. This looks great to me! > +(define-module (skribilo reader gemtext) > + #:use-module (rnrs io ports) > + #:use-module (srfi srfi-26) > + #:use-module (srfi srfi-71) > + #:use-module (srfi srfi-171) I=E2=80=99ve just realized that, currently, Skribilo supports Guile 2.x in addition to 3.0, but neither 2.2 nor 2.0 has (srfi srfi-171). Maybe the simplest option is to check for (srfi srfi-171) in configure.ac and disable compilation of this module if it=E2=80=99s unavail= able, similar to the =E2=80=98BUILD_RSS2_READER=E2=80=99 conditional. WDYT? Minor cosmetic comments: > +(skribilo-module-syntax) I think you can omit this line and use regular #:keywords. That=E2=80=99s all I have to say, thank you! Ludo=E2=80=99. From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH] reader: Add Gemtext reader. Resent-From: Arun Isaac Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Tue, 12 Apr 2022 19:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 54705@debbugs.gnu.org Received: via spool by 54705-submit@debbugs.gnu.org id=B54705.164979246232757 (code B ref 54705); Tue, 12 Apr 2022 19:42:01 +0000 Received: (at 54705) by debbugs.gnu.org; 12 Apr 2022 19:41:02 +0000 Received: from localhost ([127.0.0.1]:50115 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1neMNq-0008WG-09 for submit@debbugs.gnu.org; Tue, 12 Apr 2022 15:41:02 -0400 Received: from mugam.systemreboot.net ([139.59.75.54]:36256) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1neMNj-0008Vf-4D for 54705@debbugs.gnu.org; Tue, 12 Apr 2022 15:41:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=systemreboot.net; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-ID:Date:References:In-Reply-To:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=/D7JwyXucwefP4KwNlWjYgPQ9W/8WcRW+xtdaQWNwmc=; b=mbcdemAgqaC5tXN5zuXb/butmm kynmpn2whdRKRMPjpjYda8pEYip910+GhfxWPA4znsDeRnM+HXO0xHFDN6NM9H0/xWMmgyI362Tby ZvYsjhWNulUsZw/i/X//H8KipO7usVCyXs2WxNsmg3sCnxJW81iKM9tJvfXLZBshEJ9bQ8hLax6lS k3aQcgG0zTECdZdt/dnGMDpaVFHJgrUNlJRv+4JTUuIWT6YmyfukQB4GD+qEdeZ0uvfUbrHUaPWJJ H4uH/ooCfSgDWGtbJFxbk8a0CgSTF8/v6Bo9zEoveqz3cF2MEBuf7RGeO5jPaCXy09HuqYmLXnMGG VR62h7gg==; Received: from [192.168.2.1] (port=5408 helo=steel) by systemreboot.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1neMNg-000AmG-56; Wed, 13 Apr 2022 01:10:52 +0530 From: Arun Isaac In-Reply-To: <87a6cs66mm.fsf@gnu.org> References: <20220404092742.11963-1-arunisaac@systemreboot.net> <87a6cs66mm.fsf@gnu.org> Date: Wed, 13 Apr 2022 01:10:51 +0530 Message-ID: <87o8163xa4.fsf@systemreboot.net> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Hi Ludo, > I=E2=80=99ve just realized that, currently, Skribilo supports Guile 2.x in > addition to 3.0, but neither 2.2 nor 2.0 has (srfi srfi-171). > > Maybe the simplest option is to check for (srfi srfi-171) in > configure.ac and disable compilation of this module if it=E2=80=99s unava= ilable, > similar to the =E2=80=98BUILD_RSS2_READER=E2=80=99 conditional. > > WDYT? Sure, done! A new patch follows in my next mail. But, I have always wondered, why do we not leave all the SRFIs as external packages outside guile? That way, older versions of guile and other scheme implementations might use them as well. It's a pity that I have had to make many of guile packages strictly guile 3+ just because I use SRFI-171. >> +(skribilo-module-syntax) > > I think you can omit this line and use regular #:keywords. I'd love to do that, but if I do, doc-markup fails to read the gemtext.scm source file properly. The backtrace follows. doc-markup will have to be fixed. May I push this patch and work on that separately later? --8<---------------cut here---------------start------------->8--- Backtrace: In ice-9/eval.scm: 177:49 19 (lp _) 177:32 18 (lp (# #= # # # =E2=80=A6)) In ice-9/ports.scm: 433:17 17 (call-with-input-file _ _ #:binary _ #:encoding _ #:guess-enco= ding _) 472:4 16 (_ _) In ice-9/boot-9.scm: 2836:4 15 (save-module-excursion _) In skribilo/evaluator.scm: 61:2 14 (_) In unknown file: 13 (eval (chapter #:title "Syntax" #:ident "syntax" (p (quasiquot= e ("This chapter describes the syntax or Skribilo documents---or\nrather, t= he available syntaxes Skribilo documents can use. Skribilo\nactually suppo= rts several =E2=80=A6" =E2=80=A6))) # =E2=80=A6) =E2=80=A6) In ice-9/eval.scm: 214:21 12 (_ _) 217:50 11 (lp _) 217:50 10 (lp _) 217:50 9 (lp (# = # # # # =E2=80=A6)) 217:50 8 (lp (# = # # # #)) 217:33 7 (lp (# = # # #)) 214:21 6 (_ #f) 217:50 5 (lp (# #= #)) 217:50 4 (lp (# #= )) 217:33 3 (lp (#)) In skribilo/documentation/api.scm: 782:10 2 (%doc-markup-internal #< 140154063808512 "./syntax.s= kb":224:6> make-gemtext-reader _ #:ident _ #:writer-id _ #:common-args _ #:= ignore-args _ #:force-args _ #:idx _ #:idx-note _ #:idx-suffix _ #:source _= #:def _ #:see-also _ . #) In skribilo/lib.scm: 225:6 1 (skribe-error _ _ _) In ice-9/boot-9.scm: 1685:16 0 (raise-exception _ #:continuable? _) ice-9/boot-9.scm:1685:16: In procedure raise-exception: doc-markup: make-gemtext-reader: missing descriptions (:key join-lines? sec= tion-numbers?) --8<---------------cut here---------------end--------------->8--- Thanks, Arun From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH v2] reader: Add Gemtext reader. Resent-From: Arun Isaac Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Tue, 12 Apr 2022 19:43:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: Arun Isaac , Ludovic =?UTF-8?Q?Court=C3=A8s?= Cc: 54705@debbugs.gnu.org Received: via spool by 54705-submit@debbugs.gnu.org id=B54705.1649792562475 (code B ref 54705); Tue, 12 Apr 2022 19:43:02 +0000 Received: (at 54705) by debbugs.gnu.org; 12 Apr 2022 19:42:42 +0000 Received: from localhost ([127.0.0.1]:50126 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1neMPP-00007X-7j for submit@debbugs.gnu.org; Tue, 12 Apr 2022 15:42:42 -0400 Received: from mugam.systemreboot.net ([139.59.75.54]:36258) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1neMPM-00007N-NC for 54705@debbugs.gnu.org; Tue, 12 Apr 2022 15:42:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=systemreboot.net; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=OyACJCvKzwzrb6dsZXuY04v37EyfXNYTVMRB7eDaOPs=; b=aI4DO4/keUpYovhAeyiZjh/IIu YncS7o7Nqi0N+I5XWc+dkpu+SHip9FvfZCmyey9Y19qvG4UVlZOGxFpNBAIyWGvuHMElNM+9eti3e Zhj6rAXwuO/lWfCi3spcKQBfzM5hcZQfVtZJJ1PGxA0mVyWYf+LbNbEgOb/Q43b+AScSoPnrqOtQu F58OaRyLDKrnP7ZUHTSgIgACnhlLW+6tUJskW60zFZCGaKy/bnoBWsDshG0hMdegfgnAjsqJ7jK5x //D/7G9Th6q9igv/Mu+mwRYopqjhp7XRnNKx97ydi+kJpOW1A0wtX9qhpxvwH1UEbVDmWAshrDp6p HFGEY/WQ==; Received: from [192.168.2.1] (port=6708 helo=localhost.localdomain) by systemreboot.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1neMPK-000Ame-5y; Wed, 13 Apr 2022 01:12:34 +0530 From: Arun Isaac Date: Wed, 13 Apr 2022 01:12:32 +0530 Message-Id: <20220412194232.16496-1-arunisaac@systemreboot.net> X-Mailer: git-send-email 2.35.1 In-Reply-To: <87o8163xa4.fsf@systemreboot.net> References: <87o8163xa4.fsf@systemreboot.net> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Score: 1.6 (+) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: * src/guile/skribilo/reader/gemtext.scm: New file. * configure.ac: Set BUILD_GEMTEXT_READER automake conditional to true if (srfi srfi-171) is found. Else, set it to false. * src/guile/Makefile.am (re [...] Content analysis details: (1.6 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 1.6 PDS_OTHER_BAD_TLD Untrustworthy TLDs [URI: gemini.circumlunar.space (space)] -0.0 T_SCC_BODY_TEXT_LINE No description available. X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 0.6 (/) * src/guile/skribilo/reader/gemtext.scm: New file. * configure.ac: Set BUILD_GEMTEXT_READER automake conditional to true if (srfi srfi-171) is found. Else, set it to false. * src/guile/Makefile.am (readers): Add skribilo/reader/gemtext.scm if BUILD_GEMTEXT_READER is true. (EXTRA_DIST): Add skribilo/reader/gemtext.scm if BUILD_GEMTEXT_READER is false. * doc/user/syntax.skb (The Gemtext Syntax): New section. * tests/readers/gemtext.test: New file. * tests/Makefile.am (TESTS): Add readers/gemtext.test if BUILD_GEMTEXT_READER is true. (EXTRA_DIST): Add readers/gemtext.text if BUILD_GEMTEXT_READER is false. --- configure.ac | 9 + doc/user/syntax.skb | 21 ++- src/guile/Makefile.am | 10 ++ src/guile/skribilo/reader/gemtext.scm | 231 ++++++++++++++++++++++++++ tests/Makefile.am | 10 ++ tests/readers/gemtext.test | 133 +++++++++++++++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 src/guile/skribilo/reader/gemtext.scm create mode 100644 tests/readers/gemtext.test diff --git a/configure.ac b/configure.ac index 04c7eac..5ad964a 100644 --- a/configure.ac +++ b/configure.ac @@ -66,6 +66,15 @@ fi AM_CONDITIONAL([BUILD_RSS2_READER], [test "x$have_sxml_simple$have_htmlprag" == "xyesyes"]) +# Check for SRFI-171, needed for the `gemtext' reader. +GUILE_MODULE_AVAILABLE([have_srfi_171], [(srfi srfi-171)]) +if test "x$have_srfi_171" != "xyes"; then + AC_MSG_WARN([SRFI-171 needed by the `gemtext' reader is missing.]) +fi + +AM_CONDITIONAL([BUILD_GEMTEXT_READER], + [test "x$have_srfi_171" == "xyes"]) + # Look for `convert', from ImageMagick. AC_PATH_PROG([CONVERT], [convert]) if test "x$CONVERT" == "x"; then diff --git a/doc/user/syntax.skb b/doc/user/syntax.skb index 9a4070c..2de7cbd 100644 --- a/doc/user/syntax.skb +++ b/doc/user/syntax.skb @@ -211,7 +211,26 @@ documents that can be output in variety of formats (see ,(numref :text [Chapter] :ident "engines")). The downside is that, being a very simple markup-less document format, there are many things that cannot be done using it, most notably tables, bibliographies, and cross-references.])) - + + (section :title [The Gemtext Syntax] :ident "gemtext-syntax" + (p [,(ref +:url "https://gemini.circumlunar.space/docs/gemtext.gmi" +:text "Gemtext"), the lightweight markup language used by the ,(ref +:url "https://gemini.circumlunar.space" :text "Gemini protocol"), is +supported as an input syntax. To use it, just pass ,(tt +[--reader=gemtext]) to the compiler. When used programmatically, the +Gemtext reader can be customized using the following options.]) + + (doc-markup 'make-gemtext-reader + '((:join-lines? [If ,(code "#t"), lines which are not +separated by a blank line are joined into a single paragraph. This is +a relaxation of the Gemtext standard, and is not done by default.]) + (:section-numbers? [If ,(code "#t"), sections are +numbered. Else, they are not.])) + :common-args '() + :source "skribilo/reader/gemtext.scm" + :idx *function-index*)) + (section :title [The RSS 2.0 Syntax] :ident "rss2-syntax" diff --git a/src/guile/Makefile.am b/src/guile/Makefile.am index 98f2873..09bb7da 100644 --- a/src/guile/Makefile.am +++ b/src/guile/Makefile.am @@ -1,5 +1,6 @@ # Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2012, # 2015, 2018, 2020 Ludovic Courtès +# Copyright 2022 Arun Isaac # # This file is part of Skribilo. # @@ -59,6 +60,15 @@ EXTRA_DIST += skribilo/reader/rss-2.scm endif !BUILD_RSS2_READER +if BUILD_GEMTEXT_READER + +readers += skribilo/reader/gemtext.scm + +else !BUILD_GEMTEXT_READER + +EXTRA_DIST += skribilo/reader/gemtext.scm + +endif !BUILD_GEMTEXT_READER engines = \ skribilo/engine/base.scm skribilo/engine/context.scm \ diff --git a/src/guile/skribilo/reader/gemtext.scm b/src/guile/skribilo/reader/gemtext.scm new file mode 100644 index 0000000..7f5905c --- /dev/null +++ b/src/guile/skribilo/reader/gemtext.scm @@ -0,0 +1,231 @@ +;;; gemtext.scm -- A reader for the Gemini protocol's Gemtext markup +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (skribilo reader gemtext) + #:use-module (rnrs io ports) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) + #:use-module (srfi srfi-171) + #:use-module (ice-9 match) + #:use-module ((ice-9 textual-ports) #:select (unget-char unget-string)) + #:use-module (skribilo reader) + #:use-module (skribilo utils syntax) + #:export (reader-specification + make-gemtext-reader)) + +(skribilo-module-syntax) + +;;; Author: Arun Isaac +;;; +;;; Commentary: +;;; +;;; A reader for gemtext, the lightweight markup language used by the +;;; Gemini protocol +;;; +;;; Code: + +(define %join-lines? + (make-parameter #f)) + +(define %section-numbers? + (make-parameter #f)) + +(define (string-blank? str) + "Return #t if STR contains only whitespace characters. Else, return +#f." + (string-every char-set:whitespace str)) + +(define (string-remove-prefix prefix str) + "Return STR with PREFIX removed. If PREFIX is not a prefix of STR, +return #f." + (and (string-prefix? prefix str) + (substring str (string-length prefix)))) + +(define (string-partition str char-pred) + "Return the part of STR before and after the first occurrence of +CHAR-PRED as two values." + (let ((partition-index (string-index str char-pred))) + (if partition-index + (values (substring str 0 partition-index) + (substring str partition-index)) + (values str #f)))) + +(define (unget-line port line) + "Place the string LINE in PORT so that subsequent read operations +will read LINE followed by a newline character." + (unget-char port #\newline) + (unget-string port line)) + +(define (read-preformatted-text in out) + "Read preformatted text from port IN and write it to port OUT." + (let ((line (get-line in))) + (unless (or (eof-object? line) + (string-prefix? "```" line)) + (put-string out line) + (newline out) + (read-preformatted-text in out)))) + +(define (heading-level line) + "Return the level of the heading in LINE. If LINE is not a heading, +return #f." + (cond + ((string-prefix? "### " line) 3) + ((string-prefix? "## " line) 2) + ((string-prefix? "# " line) 1) + (else #f))) + +(define (read-section-children level port) + "Read section elements of LEVEL from PORT. Return as a list." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) (list)) + ;; If another heading of same or higher level begins, unget line + ;; and end section. + ((let ((heading-level (heading-level line))) + (and heading-level + (<= heading-level level))) + (unget-line port line) + (list)) + ;; If blank line, continue. + ((string-blank? line) + (read-section-children level port)) + ;; Else, add element and continue. + (else + (unget-line port line) + (cons (read-gemtext-element port) + (read-section-children level port)))))) + +(define (paragraph-line? line) + "Return #t if LINE is a paragraph line. Else, return #f." + (not (or (string-blank? line) + (heading-level line) + (string-prefix? "* " line) + (string-prefix? ">" line) + (string-prefix? "=>" line) + (string-prefix? "```" line)))) + +(define (link-line->item line) + "Convert link LINE to a skribilo ref expression." + (let* ((trimmed-line (string-trim (string-remove-prefix "=>" line))) + (url text (string-partition trimmed-line (char-set #\space #\tab)))) + (if text + `(item (ref #:url ,url #:text ,(string-trim text))) + `(item (ref #:url ,url))))) + +(define (retf-unget-line port result line) + "Unget LINE to PORT and return RESULT. This function is used as an +argument to ttake-while." + (unget-line port line) + result) + +(define (read-gemtext-element port) + "Read next gemtext element from PORT." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) line) + ;; Section + ((heading-level line) + => (lambda (level) + `(,(case level + ((1) 'section) + ((2) 'subsection) + ((3) 'subsubsection)) + #:title ,(substring line (1+ level)) + #:number ,(%section-numbers?) + ,@(read-section-children level port)))) + ;; List + ((string-remove-prefix "* " line) + => (lambda (first-item) + `(itemize + ,@(port-transduce (compose (ttake-while (cut string-prefix? "* " <>) + (cut retf-unget-line port <> <>)) + (tmap (lambda (line) + `(item ,(string-remove-prefix "* " line))))) + rcons + (list `(item ,first-item)) + get-line + port)))) + ;; Blockquote + ((string-remove-prefix ">" line) + => (lambda (first-line) + (list 'blockquote + (if (%join-lines?) + (string-join + (port-transduce (compose (ttake-while (cut string-prefix? ">" <>) + (cut retf-unget-line port <> <>)) + (tmap (cut string-remove-prefix ">" <>))) + rcons + (list first-line) + get-line + port) + " ") + line)))) + ;; Link + ((string-prefix? "=>" line) + (cons 'itemize + (port-transduce (compose (ttake-while (cut string-prefix? "=>" <>) + (cut retf-unget-line port <> <>)) + (tmap link-line->item)) + rcons + (list (link-line->item line)) + get-line + port))) + ;; Preformatted text + ((string-remove-prefix "```" line) + => (lambda (alt-text) + ;; We don't use the alt text. + `(pre ,(call-with-output-string + (cut read-preformatted-text port <>))))) + ;; Ignore blank lines. + ((string-blank? line) (read-gemtext-element port)) + ;; Paragraph + (else + (list 'paragraph + (if (%join-lines?) + (string-join + (port-transduce (ttake-while paragraph-line? + (cut retf-unget-line port <> <>)) + rcons + (list line) + get-line + port) + " ") + line)))))) + +(define* (make-gemtext-reader :key join-lines? section-numbers?) + "Return a gemtext reader. + +If JOIN-LINES? is #t, lines which are not separated by a blank line +are joined into a single paragraph. + +If SECTION-NUMBERS? is #t, sections are numbered. Else, they are not." + (lambda (port) + (parameterize ((%join-lines? join-lines?) + (%section-numbers? section-numbers?)) + (match (port-transduce (tmap identity) + rcons + read-gemtext-element + port) + (() (eof-object)) + (elements `(document ,@elements)))))) + +(define-reader gemtext "0.1" make-gemtext-reader) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8ba7637..26b05ad 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -26,5 +26,15 @@ EXTRA_DIST = $(TESTS) readers/rss-2.test endif !BUILD_RSS2_READER +if BUILD_GEMTEXT_READER + +TESTS += readers/gemtext.test +EXTRA_DIST = $(TESTS) + +else !BUILD_GEMTEXT_READER + +EXTRA_DIST = $(TESTS) readers/gemtext.test + +endif !BUILD_GEMTEXT_READER CLEANFILES = ast.log resolve.log rss-2.log location.log info.log diff --git a/tests/readers/gemtext.test b/tests/readers/gemtext.test new file mode 100644 index 0000000..2340dc0 --- /dev/null +++ b/tests/readers/gemtext.test @@ -0,0 +1,133 @@ +;;; Exercise Gemtext reader. -*- Scheme -*- +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (tests gemtext) + #:use-module (srfi srfi-64) + #:use-module (ice-9 match) + #:use-module (skribilo reader)) + +(define make-gemtext-reader + (reader:make (lookup-reader 'gemtext))) + +(define-syntax-rule (match? exp pattern) + (match exp + (pattern #t) + (_ #f))) + + + +(test-begin "gemtext") + +(test-assert "basic gemtext document" + (match? (call-with-input-string "# Heading +* Mercury +* Gemini +* Apollo +## Subheading + +### Subsubheading + +> I contend that text-based websites should not exceed in size the major works of Russian literature. + +# Links + +=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com + +``` +This is a preformatted block. +``` + +```alt +This is a preformatted block with \"alt text\". +```" + (make-gemtext-reader)) + `(document + (section #:title "Heading" #:number #f + (itemize (item "Mercury") + (item "Gemini") + (item "Apollo")) + (subsection #:title "Subheading" #:number #f + (subsubsection #:title "Subsubheading" #:number #f + (blockquote "> I contend that text-based websites should not exceed in size the major works of Russian literature.")))) + (section #:title "Links" #:number #f + (itemize (item (ref #:url "https://example.com" #:text "A cool website")) + (item (ref #:url "gopher://example.com" #:text "An even cooler gopherhole")) + (item (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule")) + (item (ref #:url "sftp://example.com"))) + (pre "This is a preformatted block.\n") + (pre "This is a preformatted block with \"alt text\".\n"))))) + +(test-assert "do not join short lines into paragraph" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-assert "join short lines into paragraphs" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader #:join-lines? #t)) + `(document + (paragraph "Foo Bar")))) + +(test-assert "do not number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader)) + `(document + (section #:title "Foo" #:number #f + (subsection #:title "Bar" #:number #f))))) + +(test-assert "number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader #:section-numbers? #t)) + `(document + (section #:title "Foo" #:number #t + (subsection #:title "Bar" #:number #t))))) + +(test-assert "break up links separated by blank lines into separate lists" + (match? (call-with-input-string "=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole + +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com" + (make-gemtext-reader)) + `(document + (itemize (item (ref #:url "https://example.com" #:text "A cool website")) + (item (ref #:url "gopher://example.com" #:text "An even cooler gopherhole"))) + (itemize (item (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule")) + (item (ref #:url "sftp://example.com")))))) + +(test-assert "ignore blank lines that have a non-zero number of whitespace characters" + (match? (call-with-input-string "Foo + +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-end "gemtext") -- 2.35.1 From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH v2] reader: Add Gemtext reader. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Fri, 15 Apr 2022 16:37:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: Arun Isaac Cc: 54705@debbugs.gnu.org Received: via spool by 54705-submit@debbugs.gnu.org id=B54705.165004061211586 (code B ref 54705); Fri, 15 Apr 2022 16:37:02 +0000 Received: (at 54705) by debbugs.gnu.org; 15 Apr 2022 16:36:52 +0000 Received: from localhost ([127.0.0.1]:60186 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfOwF-00030n-Rl for submit@debbugs.gnu.org; Fri, 15 Apr 2022 12:36:52 -0400 Received: from eggs.gnu.org ([209.51.188.92]:49306) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfOwC-00030Y-Jh for 54705@debbugs.gnu.org; Fri, 15 Apr 2022 12:36:50 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:59292) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfOw6-0007pB-Lt; Fri, 15 Apr 2022 12:36:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:In-Reply-To:Date:References:Subject:To: From; bh=mQ/aufUVJuLAXXsNiuRPppzRKNsvGQOcDaJ3rziAc5o=; b=Efhjpr1UX+k2mgzu4dqO ED7Ripfu7V7n+r6WH/MOpgUgI8mDaTzeXouAC9karuJsNDFCOCTSRkCOADQb3aZT79uHjIaLjAlqL 60Uwi2QM1y1SmEFMFEOEkUkII73rrzp7WybREazkMqOYVy93hDbwnuaTlLHEkLjfk3t5aeNLKe16e Xxur+ovZDcvXK1XfMv38lqVu0TSRIu895FXs8xVc7MMuekB+NkCkl5JnnY+wc1tg4LfLZkAqKdgUT UQwbbS08WMUXw8DuqIJIsTbHHZXe82zfXlqLy+5iSKygfXwA9CQar9HGcNYAlMGM9qJjAAb3yzFfF TKyE5RdkDUUX1A==; Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:51324 helo=ribbon) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfOw6-00074t-9R; Fri, 15 Apr 2022 12:36:42 -0400 From: Ludovic =?UTF-8?Q?Court=C3=A8s?= References: <87o8163xa4.fsf@systemreboot.net> <20220412194232.16496-1-arunisaac@systemreboot.net> X-URL: http://www.fdn.fr/~lcourtes/ X-Revolutionary-Date: 26 Germinal an 230 de la =?UTF-8?Q?R=C3=A9volution?= X-PGP-Key-ID: 0x090B11993D9AEBB5 X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4 0CFB 090B 1199 3D9A EBB5 X-OS: x86_64-pc-linux-gnu Date: Fri, 15 Apr 2022 18:36:39 +0200 In-Reply-To: <20220412194232.16496-1-arunisaac@systemreboot.net> (Arun Isaac's message of "Wed, 13 Apr 2022 01:12:32 +0530") Message-ID: <878rs6482w.fsf@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Hi! Arun Isaac skribis: > * src/guile/skribilo/reader/gemtext.scm: New file. > * configure.ac: Set BUILD_GEMTEXT_READER automake conditional to true > if (srfi srfi-171) is found. Else, set it to false. > * src/guile/Makefile.am (readers): Add skribilo/reader/gemtext.scm > if BUILD_GEMTEXT_READER is true. > (EXTRA_DIST): Add skribilo/reader/gemtext.scm if BUILD_GEMTEXT_READER > is false. > * doc/user/syntax.skb (The Gemtext Syntax): New section. > * tests/readers/gemtext.test: New file. > * tests/Makefile.am (TESTS): Add readers/gemtext.test if > BUILD_GEMTEXT_READER is true. > (EXTRA_DIST): Add readers/gemtext.text if BUILD_GEMTEXT_READER is > false. LGTM, thanks! Ludo=E2=80=99. From unknown Tue Jun 17 01:46:48 2025 X-Loop: help-debbugs@gnu.org Subject: bug#54705: [PATCH] reader: Add Gemtext reader. Resent-From: Ludovic =?UTF-8?Q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: skribilo-bugs@nongnu.org Resent-Date: Fri, 15 Apr 2022 16:38:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54705 X-GNU-PR-Package: skribilo X-GNU-PR-Keywords: patch To: Arun Isaac Cc: 54705@debbugs.gnu.org Received: via spool by 54705-submit@debbugs.gnu.org id=B54705.165004064111663 (code B ref 54705); Fri, 15 Apr 2022 16:38:01 +0000 Received: (at 54705) by debbugs.gnu.org; 15 Apr 2022 16:37:21 +0000 Received: from localhost ([127.0.0.1]:60191 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfOwj-000323-4p for submit@debbugs.gnu.org; Fri, 15 Apr 2022 12:37:21 -0400 Received: from eggs.gnu.org ([209.51.188.92]:49406) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfOwh-00031o-5A for 54705@debbugs.gnu.org; Fri, 15 Apr 2022 12:37:20 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:59300) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfOwb-0007xI-MS; Fri, 15 Apr 2022 12:37:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:In-Reply-To:Date:References:Subject:To: From; bh=Ps6b9dZY9PRtlB8CoVCEYzDVb8eNcivYYN0GoIgSwi8=; b=ghGzp9tVeOzblw22ewDh AtyYRvh38jsl5NyCcRzoP87bVzACmSN2xmkcL2Eq4Gs3E4Q6f/tREZwecvmpobYkS8gfIp8VwZ6Wu JwNce+I34QmvMwove0mRWdCPYsbP0bgE6j0fvFq46RoMk1BU1Ot6pBnBVyz5sDhQASFMb4CQMJEWb GxWrsWsoEFQIGiEU2C6JZx5nyq/ZbL0Ux67//62/lPKebItpjc5yfrfmnmMgEYeBpR0t1xzhWzy5V 9AwgBlngO4V4Pi2DF5B6kQDH0Oj5NobiZeQwFIBvsAUlc1xExTf0AqaWIwvz5Q4DD3q4hLmlFpkD4 2Oxn6ZOWnDW1Sw==; Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:50248 helo=ribbon) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfOwa-0007Cz-MJ; Fri, 15 Apr 2022 12:37:13 -0400 From: Ludovic =?UTF-8?Q?Court=C3=A8s?= References: <20220404092742.11963-1-arunisaac@systemreboot.net> <87a6cs66mm.fsf@gnu.org> <87o8163xa4.fsf@systemreboot.net> X-URL: http://www.fdn.fr/~lcourtes/ X-Revolutionary-Date: 26 Germinal an 230 de la =?UTF-8?Q?R=C3=A9volution?= X-PGP-Key-ID: 0x090B11993D9AEBB5 X-PGP-Key: http://www.fdn.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 3CE4 6455 8A84 FDC6 9DB4 0CFB 090B 1199 3D9A EBB5 X-OS: x86_64-pc-linux-gnu Date: Fri, 15 Apr 2022 18:37:11 +0200 In-Reply-To: <87o8163xa4.fsf@systemreboot.net> (Arun Isaac's message of "Wed, 13 Apr 2022 01:10:51 +0530") Message-ID: <874k2u4820.fsf@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Arun Isaac skribis: > I'd love to do that, but if I do, doc-markup fails to read the > gemtext.scm source file properly. The backtrace follows. doc-markup will > have to be fixed. May I push this patch and work on that separately > later? Yeah, let=E2=80=99s fix =E2=80=98doc-markup=E2=80=99 later. Ludo=E2=80=99. From unknown Tue Jun 17 01:46:48 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: Arun Isaac Subject: bug#54705: closed (Re: [PATCH v2] reader: Add Gemtext reader.) Message-ID: References: <87h76u1ecr.fsf@systemreboot.net> <20220404092742.11963-1-arunisaac@systemreboot.net> X-Gnu-PR-Message: they-closed 54705 X-Gnu-PR-Package: skribilo X-Gnu-PR-Keywords: patch Reply-To: 54705@debbugs.gnu.org Date: Fri, 15 Apr 2022 16:50:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1650041402-13107-1" This is a multi-part message in MIME format... ------------=_1650041402-13107-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #54705: [PATCH] reader: Add Gemtext reader. which was filed against the skribilo package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 54705@debbugs.gnu.org. --=20 54705: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D54705 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1650041402-13107-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 54705-done) by debbugs.gnu.org; 15 Apr 2022 16:49:32 +0000 Received: from localhost ([127.0.0.1]:60214 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfP8W-0003Oc-2s for submit@debbugs.gnu.org; Fri, 15 Apr 2022 12:49:32 -0400 Received: from mugam.systemreboot.net ([139.59.75.54]:36266) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfP8S-0003OO-Hm for 54705-done@debbugs.gnu.org; Fri, 15 Apr 2022 12:49:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=systemreboot.net; s=default; h=Content-Type:MIME-Version:Message-ID:Date: References:In-Reply-To:Subject:Cc:To:From:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=2KTQT9Ih8mabdfaa7qYfRfoGfIHHFcxm9n15+pLG4vk=; b=kFr45fY122zX5MeP0xNNYeB6gt UONbKBMlcYIdC5Mzd8t1WJAVS7g7tFCP31eRIq2e/j6TqApAJ0tdt9fQVNx5InhMw8c6bTDYB/YaK nGC8CWQQR4YdY6Q4cqJuXiMOW8QkD5oDgdeTrF0+WHeqqVJ6yjHXZG5d70CGGLM4LjIyvAlPkW2RB Bj3B6PfCq24W9XI3JGirvYYSjidQVTfGbQZstkbGPhPuHLhi/rFoAnUTb0CcpePaEwxsSLbqgEJWg Xe21ngep9QR9uwSyE6jIjD9wh5Tjc3dlIouXFCZfq1GB1qmHMXAnVrBn0mtfU5gyLmRGcXbvDj+mH SHbob42g==; Received: from [192.168.2.1] (port=5988 helo=steel) by systemreboot.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nfP8P-000KIy-9X; Fri, 15 Apr 2022 22:19:25 +0530 From: Arun Isaac To: Ludovic =?utf-8?Q?Court=C3=A8s?= Subject: Re: [PATCH v2] reader: Add Gemtext reader. In-Reply-To: <878rs6482w.fsf@gnu.org> References: <87o8163xa4.fsf@systemreboot.net> <20220412194232.16496-1-arunisaac@systemreboot.net> <878rs6482w.fsf@gnu.org> Date: Fri, 15 Apr 2022 22:19:24 +0530 Message-ID: <87h76u1ecr.fsf@systemreboot.net> MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 54705-done Cc: 54705-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Pushed, thanks! ------------=_1650041402-13107-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 4 Apr 2022 09:28:09 +0000 Received: from localhost ([127.0.0.1]:50507 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nbJ0K-0008UK-9u for submit@debbugs.gnu.org; Mon, 04 Apr 2022 05:28:09 -0400 Received: from lists.gnu.org ([209.51.188.17]:45586) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nbJ0H-0008UB-Kn for submit@debbugs.gnu.org; Mon, 04 Apr 2022 05:28:06 -0400 Received: from eggs.gnu.org ([209.51.188.92]:58392) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nbJ0H-0002w5-5K for skribilo-bugs@nongnu.org; Mon, 04 Apr 2022 05:28:05 -0400 Received: from mugam.systemreboot.net ([139.59.75.54]:55548) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nbJ0A-00083b-LN for skribilo-bugs@nongnu.org; Mon, 04 Apr 2022 05:28:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=systemreboot.net; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=cVWc6jhW9XrPEgHYJg9wKKNZs9WeoWtKEIQb4t2SkHY=; b=EOl6+mSXLGkwFXJQoP85zkTyDy PfXh0y1fIVSQ+nO5VR3uIfbKDDGmW970JV5WAY4NkTYiFpHENZ87nCLV7s8xf3PaXgkkLRyCPgJ0C 9JrZSnFf1QUo6AygHEEYO6MEJd8T2RkRd5WKR5A4v4PpvrqCIibLVGP0x0dG/2uvPhunmhy2+EFDW f25/QqAXguv4lhHBHMkP6YAghvpNSw/7n7mp+dlMWzTR7qtcV0EdVS7KKpLimu3dhJyRvBXeMTAJH EbTuSryB6FtK4/3TaBry2VpHfbdOEH1gzPFUV6JOJsu+2GronuLCP99a5oumQr1naIWuU/T3P2X9g nDB1WxjA==; Received: from [192.168.2.1] (port=58192 helo=localhost.localdomain) by systemreboot.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1nbJ02-000g5P-DZ; Mon, 04 Apr 2022 14:57:50 +0530 From: Arun Isaac To: skribilo-bugs@nongnu.org Subject: [PATCH] reader: Add Gemtext reader. Date: Mon, 4 Apr 2022 14:57:42 +0530 Message-Id: <20220404092742.11963-1-arunisaac@systemreboot.net> X-Mailer: git-send-email 2.34.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=139.59.75.54; envelope-from=arunisaac@systemreboot.net; helo=mugam.systemreboot.net X-Spam_score_int: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, PDS_OTHER_BAD_TLD=1.997, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Score: 0.2 (/) X-Debbugs-Envelope-To: submit Cc: Arun Isaac X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.8 (/) * src/guile/skribilo/reader/gemtext.scm: New file. * src/guile/Makefile.am (readers): Register it. * doc/user/syntax.skb (The Gemtext Syntax): New section. * tests/readers/gemtext.test: New file. * tests/Makefile.am (TESTS): Add readers/gemtext.test. --- doc/user/syntax.skb | 21 ++- src/guile/Makefile.am | 3 +- src/guile/skribilo/reader/gemtext.scm | 231 ++++++++++++++++++++++++++ tests/Makefile.am | 3 +- tests/readers/gemtext.test | 133 +++++++++++++++ 5 files changed, 388 insertions(+), 3 deletions(-) create mode 100644 src/guile/skribilo/reader/gemtext.scm create mode 100644 tests/readers/gemtext.test diff --git a/doc/user/syntax.skb b/doc/user/syntax.skb index 9a4070c..2de7cbd 100644 --- a/doc/user/syntax.skb +++ b/doc/user/syntax.skb @@ -211,7 +211,26 @@ documents that can be output in variety of formats (see ,(numref :text [Chapter] :ident "engines")). The downside is that, being a very simple markup-less document format, there are many things that cannot be done using it, most notably tables, bibliographies, and cross-references.])) - + + (section :title [The Gemtext Syntax] :ident "gemtext-syntax" + (p [,(ref +:url "https://gemini.circumlunar.space/docs/gemtext.gmi" +:text "Gemtext"), the lightweight markup language used by the ,(ref +:url "https://gemini.circumlunar.space" :text "Gemini protocol"), is +supported as an input syntax. To use it, just pass ,(tt +[--reader=gemtext]) to the compiler. When used programmatically, the +Gemtext reader can be customized using the following options.]) + + (doc-markup 'make-gemtext-reader + '((:join-lines? [If ,(code "#t"), lines which are not +separated by a blank line are joined into a single paragraph. This is +a relaxation of the Gemtext standard, and is not done by default.]) + (:section-numbers? [If ,(code "#t"), sections are +numbered. Else, they are not.])) + :common-args '() + :source "skribilo/reader/gemtext.scm" + :idx *function-index*)) + (section :title [The RSS 2.0 Syntax] :ident "rss2-syntax" diff --git a/src/guile/Makefile.am b/src/guile/Makefile.am index 98f2873..0a66a88 100644 --- a/src/guile/Makefile.am +++ b/src/guile/Makefile.am @@ -47,7 +47,8 @@ SOURCES = \ SOURCES += $(readers) $(packages) $(engines) readers = \ - skribilo/reader/skribe.scm skribilo/reader/outline.scm + skribilo/reader/skribe.scm skribilo/reader/outline.scm \ + skribilo/reader/gemtext.scm if BUILD_RSS2_READER diff --git a/src/guile/skribilo/reader/gemtext.scm b/src/guile/skribilo/reader/gemtext.scm new file mode 100644 index 0000000..4ae403c --- /dev/null +++ b/src/guile/skribilo/reader/gemtext.scm @@ -0,0 +1,231 @@ +;;; gemtext.scm -- A reader for the Gemini protocol's Gemtext markup +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (skribilo reader gemtext) + #:use-module (rnrs io ports) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) + #:use-module (srfi srfi-171) + #:use-module (ice-9 match) + #:use-module ((ice-9 textual-ports) #:select (unget-char unget-string)) + #:use-module (skribilo reader) + #:use-module (skribilo utils syntax) + #:export (reader-specification + make-gemtext-reader)) + +(skribilo-module-syntax) + +;;; Author: Arun Isaac +;;; +;;; Commentary: +;;; +;;; A reader for gemtext, the lightweight markup language used by the +;;; Gemini protocol +;;; +;;; Code: + +(define %join-lines? + (make-parameter #f)) + +(define %section-numbers? + (make-parameter #f)) + +(define (string-blank? str) + "Return #t if STR contains only whitespace characters. Else, return +#f." + (string-every char-set:whitespace str)) + +(define (string-remove-prefix prefix str) + "Return STR with PREFIX removed. If PREFIX is not a prefix of STR, +return #f." + (and (string-prefix? prefix str) + (substring str (string-length prefix)))) + +(define (string-partition str char-pred) + "Return the part of STR before and after the first occurrence of +CHAR-PRED as two values." + (let ((partition-index (string-index str char-pred))) + (if partition-index + (values (substring str 0 partition-index) + (substring str partition-index)) + (values str #f)))) + +(define (unget-line port line) + "Place the string LINE in PORT so that subsequent read operations +will read LINE followed by a newline character." + (unget-char port #\newline) + (unget-string port line)) + +(define (read-preformatted-text in out) + "Read preformatted text from port IN and write it to port OUT." + (let ((line (get-line in))) + (unless (or (eof-object? line) + (string-prefix? "```" line)) + (put-string out line) + (newline out) + (read-preformatted-text in out)))) + +(define (heading-level line) + "Return the level of the heading in LINE. If LINE is not a heading, +return #f." + (cond + ((string-prefix? "### " line) 3) + ((string-prefix? "## " line) 2) + ((string-prefix? "# " line) 1) + (else #f))) + +(define (read-section-children level port) + "Read section elements of LEVEL from PORT. Return as a list." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) (list)) + ;; If another heading of same or higher level begins, unget line + ;; and end section. + ((let ((heading-level (heading-level line))) + (and heading-level + (<= heading-level level))) + (unget-line port line) + (list)) + ;; If blank line, continue. + ((string-blank? line) + (read-section-children level port)) + ;; Else, add element and continue. + (else + (unget-line port line) + (cons (read-gemtext-element port) + (read-section-children level port)))))) + +(define (paragraph-line? line) + "Return #t if LINE is a paragraph line. Else, return #f." + (not (or (string-blank? line) + (heading-level line) + (string-prefix? "* " line) + (string-prefix? ">" line) + (string-prefix? "=>" line) + (string-prefix? "```" line)))) + +(define (link-line->ref line) + "Convert link LINE to a skribilo ref expression." + (let* ((trimmed-line (string-trim (string-remove-prefix "=>" line))) + (url text (string-partition trimmed-line (char-set #\space #\tab)))) + (if text + `(ref #:url ,url #:text ,(string-trim text)) + `(ref #:url ,url)))) + +(define (retf-unget-line port result line) + "Unget LINE to PORT and return RESULT. This function is used as an +argument to ttake-while." + (unget-line port line) + result) + +(define (read-gemtext-element port) + "Read next gemtext element from PORT." + (let ((line (get-line port))) + (cond + ;; End of file + ((eof-object? line) line) + ;; Section + ((heading-level line) + => (lambda (level) + `(,(case level + ((1) 'section) + ((2) 'subsection) + ((3) 'subsubsection)) + #:title ,(substring line (1+ level)) + #:number ,(%section-numbers?) + ,@(read-section-children level port)))) + ;; List + ((string-remove-prefix "* " line) + => (lambda (first-item) + `(itemize + ,@(port-transduce (compose (ttake-while (cut string-prefix? "* " <>) + (cut retf-unget-line port <> <>)) + (tmap (lambda (line) + `(item ,(string-remove-prefix "* " line))))) + rcons + (list `(item ,first-item)) + get-line + port)))) + ;; Blockquote + ((string-remove-prefix ">" line) + => (lambda (first-line) + (list 'blockquote + (if (%join-lines?) + (string-join + (port-transduce (compose (ttake-while (cut string-prefix? ">" <>) + (cut retf-unget-line port <> <>)) + (tmap (cut string-remove-prefix ">" <>))) + rcons + (list first-line) + get-line + port) + " ") + line)))) + ;; Link + ((string-prefix? "=>" line) + (cons 'paragraph + (port-transduce (compose (ttake-while (cut string-prefix? "=>" <>) + (cut retf-unget-line port <> <>)) + (tmap link-line->ref)) + rcons + (list (link-line->ref line)) + get-line + port))) + ;; Preformatted text + ((string-remove-prefix "```" line) + => (lambda (alt-text) + ;; We don't use the alt text. + `(pre ,(call-with-output-string + (cut read-preformatted-text port <>))))) + ;; Ignore blank lines. + ((string-blank? line) (read-gemtext-element port)) + ;; Paragraph + (else + (list 'paragraph + (if (%join-lines?) + (string-join + (port-transduce (ttake-while paragraph-line? + (cut retf-unget-line port <> <>)) + rcons + (list line) + get-line + port) + " ") + line)))))) + +(define* (make-gemtext-reader :key join-lines? section-numbers?) + "Return a gemtext reader. + +If JOIN-LINES? is #t, lines which are not separated by a blank line +are joined into a single paragraph. + +If SECTION-NUMBERS? is #t, sections are numbered. Else, they are not." + (lambda (port) + (parameterize ((%join-lines? join-lines?) + (%section-numbers? section-numbers?)) + (match (port-transduce (tmap identity) + rcons + read-gemtext-element + port) + (() (eof-object)) + (elements `(document ,@elements)))))) + +(define-reader gemtext "0.1" make-gemtext-reader) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8ba7637..16478a9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -13,7 +13,8 @@ TESTS = \ ast.test \ resolve.test \ engines/info.test \ - location.test + location.test \ + readers/gemtext.test if BUILD_RSS2_READER diff --git a/tests/readers/gemtext.test b/tests/readers/gemtext.test new file mode 100644 index 0000000..99891c8 --- /dev/null +++ b/tests/readers/gemtext.test @@ -0,0 +1,133 @@ +;;; Exercise Gemtext reader. -*- Scheme -*- +;;; +;;; Copyright © 2022 Arun Isaac +;;; +;;; +;;; This file is part of Skribilo. +;;; +;;; Skribilo is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Skribilo is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Skribilo. If not, see . + +(define-module (tests gemtext) + #:use-module (srfi srfi-64) + #:use-module (ice-9 match) + #:use-module (skribilo reader)) + +(define make-gemtext-reader + (reader:make (lookup-reader 'gemtext))) + +(define-syntax-rule (match? exp pattern) + (match exp + (pattern #t) + (_ #f))) + + + +(test-begin "gemtext") + +(test-assert "basic gemtext document" + (match? (call-with-input-string "# Heading +* Mercury +* Gemini +* Apollo +## Subheading + +### Subsubheading + +> I contend that text-based websites should not exceed in size the major works of Russian literature. + +# Links + +=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com + +``` +This is a preformatted block. +``` + +```alt +This is a preformatted block with \"alt text\". +```" + (make-gemtext-reader)) + `(document + (section #:title "Heading" #:number #f + (itemize (item "Mercury") + (item "Gemini") + (item "Apollo")) + (subsection #:title "Subheading" #:number #f + (subsubsection #:title "Subsubheading" #:number #f + (blockquote "> I contend that text-based websites should not exceed in size the major works of Russian literature.")))) + (section #:title "Links" #:number #f + (paragraph (ref #:url "https://example.com" #:text "A cool website") + (ref #:url "gopher://example.com" #:text "An even cooler gopherhole") + (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule") + (ref #:url "sftp://example.com")) + (pre "This is a preformatted block.\n") + (pre "This is a preformatted block with \"alt text\".\n"))))) + +(test-assert "do not join short lines into paragraph" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-assert "join short lines into paragraphs" + (match? (call-with-input-string "Foo +Bar" + (make-gemtext-reader #:join-lines? #t)) + `(document + (paragraph "Foo Bar")))) + +(test-assert "do not number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader)) + `(document + (section #:title "Foo" #:number #f + (subsection #:title "Bar" #:number #f))))) + +(test-assert "number sections" + (match? (call-with-input-string "# Foo +## Bar" + (make-gemtext-reader #:section-numbers? #t)) + `(document + (section #:title "Foo" #:number #t + (subsection #:title "Bar" #:number #t))))) + +(test-assert "break up links separated by blank lines into paragraphs" + (match? (call-with-input-string "=>https://example.com A cool website +=>gopher://example.com An even cooler gopherhole + +=> gemini://example.com A supremely cool Gemini capsule +=> sftp://example.com" + (make-gemtext-reader)) + `(document + (paragraph (ref #:url "https://example.com" #:text "A cool website") + (ref #:url "gopher://example.com" #:text "An even cooler gopherhole")) + (paragraph (ref #:url "gemini://example.com" #:text "A supremely cool Gemini capsule") + (ref #:url "sftp://example.com"))))) + +(test-assert "ignore blank lines that have a non-zero number of whitespace characters" + (match? (call-with-input-string "Foo + +Bar" + (make-gemtext-reader)) + `(document + (paragraph "Foo") + (paragraph "Bar")))) + +(test-end "gemtext") -- 2.34.0 ------------=_1650041402-13107-1--