{"id":17573049,"url":"https://github.com/fare/scribble","last_synced_at":"2026-01-08T00:06:12.502Z","repository":{"id":66597385,"uuid":"53280667","full_name":"fare/scribble","owner":"fare","description":"Scribble document syntax in Common Lisp — mirror from https://gitlab.common-lisp.net/frideau/scribble","archived":false,"fork":false,"pushed_at":"2023-10-11T02:04:55.000Z","size":51,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-04T16:16:47.400Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://cliki.net/scribble","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-06T22:56:02.000Z","updated_at":"2024-01-01T23:38:37.000Z","dependencies_parsed_at":"2024-10-22T19:19:42.791Z","dependency_job_id":null,"html_url":"https://github.com/fare/scribble","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fare%2Fscribble","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fare%2Fscribble/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fare%2Fscribble/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fare%2Fscribble/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fare","download_url":"https://codeload.github.com/fare/scribble/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246201746,"owners_count":20739808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-21T20:24:01.747Z","updated_at":"2026-01-08T00:06:12.469Z","avatar_url":"https://github.com/fare.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scribble: SCRibe-like reader extension for Common Lisp\n\nCopyright (c) 2002-2023 by Fare Rideau \u003c fare at tunes dot org \u003e\n\u003c http://www.cliki.net/Fare%20Rideau \u003e\n\n## Home Page\n\u003c http://www.cliki.net/Scribble \u003e\n\n## License\nI generally use the Bugroff License:\n\u003c http://tunes.org/legalese/bugroff.html \u003e\n\nYou may at your leisure use the LLGPL instead:\n\u003c http://www.cliki.net/LLGPL \u003e\n\n## Dependency\nThis package depends on Meta by Jochen Schmidt, version 1.0.0 or later.\n\u003c http://www.cliki.net/Meta \u003e\nNow also: meta fare-utils fare-matcher named-readtables\n\n## Usage\nYou can enable Racket-like Scribble behavior for the macro-character `#\\@` with:\n```Lisp\n(scribble:enable-scribble-at-syntax)\n```\nAnd you can disable it with:\n```Lisp\n(scribble:disable-scribble-at-syntax)\n```\nYou may also use:\n```Lisp\n(named-readtables:in-readtable :scribble-racket)\n```\nOr:\n```Lisp\n(named-readtables:in-readtable :scribble-both)\n```\nOr:\n```Lisp\n(named-readtables:in-readtable :scribble)\n```\nFor details, see:\n\u003c http://docs.racket-lang.org/scribble/reader.html \u003e\n\nIf you additionally pass the keyword argument `:skribe t`\nYou will also have Skribe-like syntax.\n\nYou can enable only Skribe-like syntax for the macro-character `#\\[` with:\n```Lisp\n(scribble:enable-scribble-syntax)\n```\nand disable it with:\n```Lisp\n(scribble:disable-scribble-syntax)\n```\nYou may also use:\n```Lisp\n(named-readtables:in-readtable :scribble-skribe)\n```\nOr:\n```Lisp\n(named-readtables:in-readtable :scribble-both)\n```\nOr\n```Lisp\n(named-readtables:in-readtable :scribble)\n```\n\nAlternatively, you can enable behaviour for the character `#\\[`\nunder the dispatching macro-character `#\\#` using:\n```Lisp\n(scribble:enable-sub-scribble-syntax)\n(scribble:disable-sub-scribble-syntax)\n```\n\n## At-syntax\nThe syntax of text after `@` is just like\nRacket's Scribble syntax by Eli Barzilay.\nHis Scribble \"at-syntax\" is described thus:\n    \u003c http://barzilay.org/research.html \u003e\n    \u003c http://barzilay.org/misc/scribble-reader.pdf \u003e\n    \u003c http://docs.racket-lang.org/scribble/reader.html \u003e\n\n## Basic Syntax\nThe syntax of text within brackets `[...]` is Skribe-like:\n\n* Text between brackets will expand to a string containing said text,\n  unless there are escape forms in the text,\n  which are identified by a comma `#\\,`\n  followed by either an opening parenthesis `#\\(` or an opening bracket `#\\[`.\n\n* If there are escape forms in the text,\n  then the text will be split into components,\n  which will be non-empty strings and escape forms.\n  The result of parsing the text will be a `(LIST ...)` of these components.\n\n* A comma `#\\,` followed by a parenthesis `#\\(` denotes an escape form,\n  wherein a SEXP beginning with said parenthesis\n  is read and used as a component of the surrounding text.\n  For instance, `[foo ,(bar baz) quux]`\n  will (on first approximation) be read as `(LIST \"foo \" (bar baz) \" quux\")`\n  Mind the spaces being preserved around the internal form.\n\n## Extension to Scribe syntax\nScribble extends the Scribe syntax in a way that I find very convenient.\n\n* As an extension to Scribe syntax,\n  if the first character of text within bracket is an unescaped colon `#\\:`\n  then an expression after it is read that is used\n  as a \"head\" for the body of the text resulting from parsing as above.\n    `[:emph this]` is read as `(EMPH \"this\")`, and\n    `[:(font :size -1) that]` is read as `(FONT :SIZE -1 \"that\")`.\n\n* As another extension to Scribe syntax,\n  a comma `#\\,` followed by a bracket `#\\[` will also denote an escape form,\n  whereas the bracketed-text using Scribble syntax\n  is read and used as a component of the surrounding text.\n  This extension is only useful in conjunction with the previous extension.\n\n## Syntactic catches\nThere are a few possible sources of problems with the Scribe syntax,\nand solutions provided by Scribe and Scribble to avoid these problems.\n\n* A closing bracket `#\\]` closes the current text.\n  Standard Scribe syntax doesn't provide a mean\n  to include a closing bracket in bracketed text.\n\n* Conversely, so as to prevent difficult to track syntax errors\n  resulting from typos, Standard Scribe syntax forbids\n  to include an opening bracket in the text.\n\n* As an extension to Scribe syntax,\n  you can include any character in the text,\n  without triggering any special or error-raising behaviour,\n  by preceding it with a backslash character `#\\\\` in the text\n  (which preceding backslash character won't be included in the result string).\n  This is useful to include a character among\n  `#\\\\` `#\\:` `#\\,` `#\\[` `#\\]` `#\\(`.\n\n* While `#\\\\` will always be able to escape all non-alphanumeric characters,\n  including the special characters listed above,\n  future extensions may give a special meaning to `#\\\\` followed by a character\n  in the regexp range `[_a-zA-Z0-9]`.\n  If you feel the need for such an extension, I will accept patches;\n  I suppose that the C or Perl syntax is what is needed here.\n\n* In the bracket-colon `[:` syntax extension, after reading the \"head\",\n  all spacing characters\n  (`#\\space`, `#\\tab`, `#\\newline`, `#\\linefeed`, `#\\return`, `#\\page`)\n  are skipped until the next non-space character:\n  `[:head     no space!]` is read as `(HEAD \"no space!\")`.\n  To insert a space character immediately after the head,\n  just escape it using `#\\\\` as above:\n  `[:head\\ \u003c- this space]` is read as `(HEAD \" \u003c- this space\")`.\n\n* As a restriction from Scribe syntax, Scribble syntax doesn't recognize\n  the use of semi-colon `#\\;` as denoting discardable comments.\n  In Scribe, a semi-colon `#\\;` at the beginning of a line or of bracketed text\n  or of a string component of bracketed text will denote a comment,\n  whereas Scribe will ignore any text to the next end of line.\n  Scribble will include any such text in the result string.\n  You can emulate the original Scribe behaviour in this regard\n  by using the preprocessing customization feature described below.\n\n## Customization\nScribble can be customized in many ways,\nto accomodate the specificities of your markup language backend.\n\n* As an extension to Scribe semantics,\n  all strings resulting from reading bracket-delimited text `[...]`\n  (as opposed to those resulting from \"normal\" double-quote delimited `\"...\"`\n  strings that may appear inside escape forms) may be preprocessed.\n  There can be compile-time or run-time preprocessing.\n  The variable `*scribble-preprocess*` decides\n  what kind of preprocessing is done.\n  If it is `nil`, then no preprocessing is done\n  (i.e. strings from the `[...]` notation will be read as such).\n  If it is `t`, then run-time preprocessing is done,\n  via the function `pp` which itself issues\n  a dynamic call to the function `*scribble-preprocessor*`\n  if not `nil` (or else behaves as `identity`).\n  If it is a function or non-boolean symbol, then said value\n  is `funcall`'ed at read-time to preprocess the string form\n  by e.g. wrapping it into some macro evaluation.\n  Note that when using run-time preprocessing,\n  you may either lexically shadow the function `pp` or\n  dynamically rebind the variable `*scribble-preprocessor*`\n  to locally select a different preprocessor.\n  A macro `scribble:with-preprocessor` is defined to do the dynamic rebinding,\n  as in `(scribble:with-preprocessor #'string-upcase [foo])` which\n  (assuming run-time preprocessing is enabled) will evaluate to `\"FOO\"`.\n\n* Though the default behaviour of Scribble is to return\n  a (possibly preprocessed) string if there are no subcomponents,\n  and a form `(cl:list ...)` if there are multiple components,\n  you can customize this behaviour by binding the customization variable\n  `scribble:*scribble-list*` to a function that will do the job,\n  taking as many arguments as there were components (zero for empty text).\n  If you only want to keep the same general behaviour,\n  but change the head of the resulting list from `cl:list` to something else,\n  then don't modify `scribble:*scribble-list*`\n  (or bind it back to `scribble:default-scribble-list`)\n  and instead bind `scribble:*scribble-default-head*` to a symbol\n  that at evaluation time will be bound to a function\n  that will properly combine the multiple components.\n  Note that this `scribble:*scribble-list*` is processed at read-time,\n  whereas the function named by `scribble:*scribble-default-head*`\n  (if applicable) will be processed at evaluation-time.\n\n* You can select a package from which Scribble will read head forms\n  of bracket-colon syntax `[:head ...]` or `[:(head args) ...]`\n  by changing the symbol-value of `scribble:*scribble-package*`.\n  Typical use is `(setq scribbe:*scribble-package* :keyword)`\n  which will do wonders with AllegroServe's `net.html.generator`.\n  Note that this feature happens at read-time, and doesn't affect\n  the current package used to read escape forms.\n  If the `*scribble-package*` feature prevents reading\n  the arguments to structured head form arguments in the right package,\n  `[:(head form arguments) ...]`\n  then you can fall back to normal scribe syntax\n  `,(head form argument [...])`\n  or qualify the symbols in your head form by their package\n  `[:(cl:head my-package:form foo:arguments) ...]`.\n\n* You can modify the way that scribble combines\n  the head and body of bracket-colon syntax `[:`\n  by changing the value of variable `scribble:*scribble-cons*`\n  from the default value `scribble:default-scribble-cons`.\n  The function takes as parameters the head specified by bracket-colon syntax\n  and the list of components of the bracketed text,\n  and has to return the desired parse result.\n  Typically, you might want to special case the behaviour\n  according to the type of the head: cons or symbol.\n  Note that this happens at read-time.\n\n* Example functions to customize scribble for use with various backends\n  are given at the end of this file. Check functions\n    `scribble:configure-scribble`,\n    `scribble:configure-scribble-for-araneida`,\n    `scribble:configure-scribble-for-htmlgen`,\n    `scribble:configure-scribble-for-lml2`,\n    `scribble:configure-scribble-for-tml`,\n    `scribble:configure-scribble-for-who`,\n    `scribble:configure-scribble-for-yaclml`.\n  Please send me updates that include support for your favorite backend.\n\n## Example use\nExample use to enable the syntax at the REPL:\n```Lisp\n(asdf:load-system \"scribble\")\n(use-package :scribble)\n(enable-scribble-syntax)\n'[foo ,[:emph bar] ,[:(baz :size 1) quux ,(tata toto [\\:titi])] tutu]\n```\n==\u003e\n```Lisp\n(LIST (PP \"foo \") (EMPH (PP \"bar\")) (PP \" \")\n (BAZ :SIZE 1 (LIST (PP \"quux \") (TATA TOTO (PP \":titi\")))) (PP \" tutu\"))\n```\n\nExample use to read a file after having enabled the syntax:\n```Lisp\n(let ((p \"/home/fare/fare/www/liberty/white_black_magic.scr\")\n      (eof '#:eof))\n  (with-open-file (s p :direction :input :if-does-not-exist :error)\n    (loop for i = (read s nil eof nil)\n      until (eq i eof)\n      collect i)))\n```\n\nExample use to configure Scribble to produce Araneida's representation of HTML:\n```Lisp\n(configure-scribble-for-araneida-html)\n(html-stream *stdout* '[:html ...])\n```\n\n## TODO\n* Make it work with aserve, who, and other backends.\n\nShare and enjoy!\n\nFor historical information, see also Daniel Herring's partial implementation:\nhttp://lists.libcl.com/pipermail/libcl-devel-libcl.com/2010-January/000094.html\n\n\n## Naming Note\n\nEli Barzilay started using the name \"Scribble\" in 2006;\nI started using it in 2003 or earlier for my Scribe-like syntax, now Skribe-like.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffare%2Fscribble","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffare%2Fscribble","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffare%2Fscribble/lists"}