{"id":26009241,"url":"https://github.com/moderninterpreters/markup","last_synced_at":"2025-03-05T22:06:50.334Z","repository":{"id":107370950,"uuid":"212697529","full_name":"moderninterpreters/markup","owner":"moderninterpreters","description":"MARKUP provides a reader-macro to read HTML tags inside of Common Lisp code","archived":false,"fork":false,"pushed_at":"2024-12-07T00:09:29.000Z","size":127,"stargazers_count":71,"open_issues_count":2,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-12-07T00:31:35.573Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moderninterpreters.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2019-10-03T23:07:47.000Z","updated_at":"2024-12-07T00:09:33.000Z","dependencies_parsed_at":"2023-05-17T06:45:50.540Z","dependency_job_id":null,"html_url":"https://github.com/moderninterpreters/markup","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/moderninterpreters%2Fmarkup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moderninterpreters%2Fmarkup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moderninterpreters%2Fmarkup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moderninterpreters%2Fmarkup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moderninterpreters","download_url":"https://codeload.github.com/moderninterpreters/markup/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242111445,"owners_count":20073433,"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":"2025-03-05T22:02:01.785Z","updated_at":"2025-03-05T22:06:50.327Z","avatar_url":"https://github.com/moderninterpreters.png","language":"Common Lisp","readme":"# markup\n\n[![tdrhq](https://circleci.com/gh/moderninterpreters/markup.svg?style=shield)](https://app.circleci.com/pipelines/github/moderninterpreters/markup?branch=main)\n\n### Arnold Noronha \u003carnold@tdrhq.com\u003e\n\nMarkup let's you write HTML code inside of common lisp, for instance\n\n```lisp\n(let ((x \"hello\"))\n  \u003ch1\u003e,(progn x) \u003cem\u003eworld\u003c/em\u003e!\u003c/h1\u003e)\n```\n\n## Motivation\n\nThere are several HTML generation libraries for Common Lisp, for\nexample CL-WHO. However, these libraries follow the Lisp style of\nbuilding up the structure in parenthesis.\n\nFor example, it might look like something like this:\n\n\n```lisp\n;; CL-WHO syntax, not markup's\n(:p \"hello\" (:em \"world\") \"!\")\n```\n\nThere are many advantages to this structure, but there are a few\nprominent disadvantages.\n\nFirst, there's all that double-quotes that becomes hard to track.\n\nSecond, and more importantly: There are hundreds of templates and HTML\nsnippets on the internet that are hard to copy-paste into your project\nif you have to transform them into CL-WHO structures. Time is money.\n\nFinally, it's already hard to hire Lisp engineers. Don't you want to\nbe able to hire designers who might at least modify HTML they\nrecognize inside your lisp project?\n\n## Performance\n\nPerformance is not a motivation for Markup. We're focussing on\ndeveloper productivity. For instance, compared to CL-WHO we generate\nthe entire tree of HTML tags before serializing it into the stream at\nthe last step. We haven't reached a situation where this is a\nbottleneck for our use cases.\n\nBuilding the tree also lets us build more complex components that can\ngo modify the tree.\n\nIt might be possible to build a streaming version of Markup, but\nthat's not on our radar.\n\n## Full example with Hunchentoot\n\n```lisp\n(markup:enable-reader)\n\n(markup:deftag template (children \u0026key title)\n  \u003chtml\u003e\n    \u003chead\u003e\n     \u003ctitle\u003e,(progn title)\u003c/title\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      ,@(progn children)\n    \u003c/body\u003e\n  \u003c/html\u003e)\n\n(hunchentoot:define-easy-handler (foobar :uri \"/\") ()\n  (markup:write-html\n     \u003ctemplate title=\"Hello\" \u003e\n        \u003ch1\u003ehello world!\u003c/h1\u003e\n     \u003c/template\u003e))\n```\n\n## Installation\n\nmarkup is available via quicklisp\n\n```lisp\n(ql:quickload \"markup\")\n```\n\n(If that doesn't load, make sure you update your dists, `(ql:update-all-dists)`)\n\n## Editor support\n\n```emacs-lisp\n(use-package lisp-markup\n  :load-path \"~/quicklisp/dists/quicklisp/software/markup-\u003cversion\u003e-git/\"\n  :hook (lisp-mode . lisp-markup-minor-mode))\n\n;; if you don't use use-package\n(add-to-list 'load-path \"~/quicklisp/dists/quicklisp/software/markup-\u003cversion\u003e-git/\")\n(require 'lisp-markup)\n(add-hook 'lisp-mode-hook #'lisp-markup-minor-mode)\n```\n\n## FAQ\n\n### What about expressions like `(\u003c x 2)`?\n\nMarkdown requires tags to follow the `\u003c` operator, otherwise (or if it's `\u003c=`) treats it as a symbol.\n\n### Are custom tags namespaced?\n\nOf course, custom tags are just lisp symbols. So you can define a tag like `\u003cadmin:template\u003e...\u003c/admin:template\u003e`.\n\nCertain tag names are treated as special (`\u003cb\u003e`, `\u003cbody\u003e` etc.) since they're HTML elements.\n\nIf you want to output the equivalent HTML element for a tag that isn't\ntreated as special you can also specify the tag using keyword symbols `\u003c:foo\u003e..\u003c/:foo\u003e`.\n\n### How do you embed lisp code in markup?\n\nYou have already seen some examples in this README. Use `,(...)` to\nescape some lisp code that returns a single element, or ,@sexp that\nreturns a list of elements. (Side note, we really don't need to have\nboth of these, but it matches the backquote syntax much better this\nway).\n\nYou can also embed lisp code as attribute values.\n\n```lisp\n  \u003ca href=(generate-url ...) \u003e...\u003c/a\u003e\n```\n\nThat is, any expression after the an attribute is read using the\nstandard Lisp reader. A small caveat to this is that in some cases you need to have a space after the ending `\u003e`. For instance the following will result in an error:\n\n```lisp\n   ;; bad code\n   \u003ca href=url-var\u003e...\u003c/a\u003e\n   ;; correct code\n   \u003ca href=url-var \u003e...\u003c/a\u003e\n```\n\n### Is markup used in production?\n\nYes it is! Right now it's used on several websites we've\nbuilt. They've solved all of our use cases reliably. The primary\nwebsite we use this on is [Screenshotbot](http://screenshotbot.io), if\nyou're building web interfaces, you might enjoy using Screenshotbot to\nkeep testing the rendering of your UI in Continuous Integration. (For\ninstance, we use Selenium tests to generate screenshots of\nScreenshotbot's UI.)\n\nPlease do let us know if you use Markup on the sites you're\nbuilding. We'd love to include them here.\n\n## See also\n\nXHP for PHP, and JSX for React both support HTML inside of code for very similar\nmotivations.\n\n@fukamachi released [LSX](https://github.com/fukamachi/lsx) in the\nsame Quicklisp release that markup came out (although his repo goes\nback much longer, around the time I first started working on Markup\ninternally.). Functionally, it's super similar to Markup and Fukamachi\nis a pretty fantastic Lisper, and maybe in the future we should\nconsolidate.\n\n## License\n\nApache License, Version 2.0\n","funding_links":[],"categories":["REPLs ##"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderninterpreters%2Fmarkup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoderninterpreters%2Fmarkup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderninterpreters%2Fmarkup/lists"}