{"id":16345393,"url":"https://github.com/unclechu/haskell-qm-interpolated-string","last_synced_at":"2025-03-23T00:32:45.028Z","repository":{"id":45920835,"uuid":"84097074","full_name":"unclechu/haskell-qm-interpolated-string","owner":"unclechu","description":"Implementation of interpolated multiline strings that ignores indentation and trailing whitespaces","archived":false,"fork":false,"pushed_at":"2022-07-18T20:19:13.000Z","size":162,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-25T22:20:47.694Z","etag":null,"topics":["cabal","hackage","haskell","haskell-library","interpolation","library","stack","strings"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unclechu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-06T16:44:14.000Z","updated_at":"2023-10-30T19:03:52.000Z","dependencies_parsed_at":"2022-09-11T01:41:09.560Z","dependency_job_id":null,"html_url":"https://github.com/unclechu/haskell-qm-interpolated-string","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fhaskell-qm-interpolated-string","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fhaskell-qm-interpolated-string/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fhaskell-qm-interpolated-string/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unclechu%2Fhaskell-qm-interpolated-string/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unclechu","download_url":"https://codeload.github.com/unclechu/haskell-qm-interpolated-string/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244257259,"owners_count":20424127,"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":["cabal","hackage","haskell","haskell-library","interpolation","library","stack","strings"],"created_at":"2024-10-11T00:31:26.132Z","updated_at":"2025-03-23T00:32:44.566Z","avatar_url":"https://github.com/unclechu.png","language":"Haskell","readme":"# [qm|interpolated-string|]\n\n[![Hackage](https://img.shields.io/hackage/v/qm-interpolated-string.svg)](https://hackage.haskell.org/package/qm-interpolated-string)\n[![Haskell Cabal \u0026 Stack CI](https://github.com/unclechu/haskell-qm-interpolated-string/actions/workflows/haskell.yml/badge.svg)](https://github.com/unclechu/haskell-qm-interpolated-string/actions/workflows/haskell.yml)\n[![Nix CI](https://github.com/unclechu/haskell-qm-interpolated-string/actions/workflows/nix.yml/badge.svg)](https://github.com/unclechu/haskell-qm-interpolated-string/actions/workflows/nix.yml)\n\nImplementation of interpolated multiline string\n[QuasiQuoter](https://wiki.haskell.org/Quasiquotation)\nthat ignores indentation and trailing whitespaces.\n\nActually it's modification of\n[interpolatedstring-perl6](https://github.com/audreyt/interpolatedstring-perl6)\npackage. I've forked it to implement my own strings I really like.\n\nThis implementation based on `qc` from **interpolatedstring-perl6** package\nbut ignores any indentation, line breaks\n(except explicitly written using `\\n` char)\nand trailing whitespaces.\n\n* 'm' in `qm` means '**M**ultiline'.\n* 'n' in `qn` means '**N**o interpolation'.\n* 'b' in `qmb`/`qnb` means 'line **B**reaks'.\n* 's' in `qms`/`qns` means '**S**paces'.\n\nWrite a decoratively formatted string and your\ndecorative indentation and line breaks wont go to result string,\nbut when you really need it, you could just escape it using backslash.\n\n## Usage example\n\n```haskell\n{-# LANGUAGE QuasiQuotes #-}\n\nimport Text.InterpolatedString.QM\n\nmain :: IO ()\nmain = do\n  -- Hello, world! Pi is 3.14…\n  putStrLn [qms| Hello,\n                 world!\n                 Pi is {floor pi}.{floor $ (pi - 3) * 100}… |]\n\n  -- Some examples with HTML below to demonstrate the difference\n  -- between all of the quasi-quoters.\n\n  let title = \"Testing\"\n      text  = \"Some testing text\"\n\n  -- \u003carticle\u003e\u003ch1\u003eTesting\u003c/h1\u003e\u003cp\u003eSome testing text\u003c/p\u003e\u003c/article\u003e\n  putStrLn [qm|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n\n  -- \u003carticle\u003e\u003ch1\u003e{title}\u003c/h1\u003e\u003cp\u003e{text}\u003c/p\u003e\u003c/article\u003e\n  putStrLn [qn|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n\n  -- \u003carticle\u003e \u003ch1\u003eTesting\u003c/h1\u003e \u003cp\u003eSome testing text\u003c/p\u003e \u003c/article\u003e\n  putStrLn [qms|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n\n  -- \u003carticle\u003e \u003ch1\u003e{title}\u003c/h1\u003e \u003cp\u003e{text}\u003c/p\u003e \u003c/article\u003e\n  putStrLn [qns|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n\n  -- \u003carticle\u003e\n  -- \u003ch1\u003eTesting\u003c/h1\u003e\n  -- \u003cp\u003eSome testing text\u003c/p\u003e\n  -- \u003c/article\u003e\n  putStrLn [qmb|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n\n  -- \u003carticle\u003e\n  -- \u003ch1\u003e{title}\u003c/h1\u003e\n  -- \u003cp\u003e{text}\u003c/p\u003e\n  -- \u003c/article\u003e\n  putStrLn [qnb|\n    \u003carticle\u003e\n      \u003ch1\u003e{title}\u003c/h1\u003e\n      \u003cp\u003e{text}\u003c/p\u003e\n    \u003c/article\u003e\n  |]\n```\n\n## Tables\n\n### All QuasiQuoters\n\n```\n| QuasiQuoter | Interpolation | Indentation | Line breaks          | Trailing whitespaces |\n|-------------|---------------|-------------|----------------------|----------------------|\n| qm          | ✓             | Removed     | Removed              | Removed              |\n| qn          | ✗             | Removed     | Removed              | Removed              |\n| qmb         | ✓             | Removed     | Kept                 | Removed              |\n| qnb         | ✗             | Removed     | Kept                 | Removed              |\n| qms         | ✓             | Removed     | Replaced with spaces | Removed              |\n| qns         | ✗             | Removed     | Replaced with spaces | Removed              |\n```\n\n### About naming logic\n\n```\n| Contains in its name | What means                       | QuasiQuoters |\n|----------------------|----------------------------------|--------------|\n| m                    | Resolves interpolation blocks    | qm, qmb, qms |\n| n                    | Without interpolation            | qn, qnb, qns |\n| b                    | Keeps line breaks                | qmb, qnb     |\n| s                    | Replaces line breaks with spaces | qms, qns     |\n```\n\n## About interpolation blocks\n\nAlong with all specifics of any of the quoters (which supports interpolation\nblocks, which has `m` in their names) interpolation blocks work different. When\ncurly bracket (`{`) opens everything inside until it closes (by `}`) is parsed\nas bare as possible to be given to\n[haskell-src-meta](http://hackage.haskell.org/package/haskell-src-meta)\nwithout any modifications, to be parsed as bare Haskell code.\n\nBut you might need use curly brackets inside an interpolation block. I don't\nthink it would be a good idea, because complicated logic there may cause code\nreadability issues, but if you're sure you need it then you get it. You just\nneed to escape closing bracket to prevent interpolation block from closing, like\nthis: `\\}`. I know it could parsed and opening curly brackets inside could be\nused to prevent closing by next `}` symbol, but I chose do it this way to\nprevent any unobvious tricky behavior (e.g. consider `}` appear inside a string,\n`[qm|foo {'x':'}':\"y\"} bar|]`, how that should be handled?). So I've decided to\nnot make parser to be very smart, just to follow simple logic. You just need to\nexplicitly escape every `}` symbol inside that isn't closer of an interpolation\nblock (you could find an example below).\n\n## About escaping\n\n### Symbols that can be escaped\n\nBackslash is used for escaping these:\n\n  1. `\\n` - line break\n  2. `\\ ` - space (space is supposed to be escaped when you're going to keep\n            some part of indentation)\n  3. `\\↵` - backslash just before end of line cuts off line break\n            (makes sense for `qmb`, `qnb`, `qms` and `qns`)\n  4. `\\{` - opening bracket of interpolation block\n            (only for `qm`, `qmb` and `qms`, to prevent interpolation\n            and interpret this block as plain text)\n  5. `\\t` or `\\‣` (where `‣` is real tab symbol) - tab (escaping it to keep some\n     part of indentation, or if you need tab symbol for some reason,\n     escaping real tabs makes sense only for keeping some part of indentation)\n  6. `\\\\` - backslash itself (for situations when you don't want to escape\n            other symbols but just want backslash symbol, `\\\\t`, `\\\\n`, `\\\\↵`,\n            `\\\\{`, etc., if backslash doesn't come with any of symbols from\n            this list it is interpreted just as backslash symbol, keep in mind\n            that `\\\\\\` (without any of symbols from this list after)\n            and `\\\\\\\\` are producing same result - `\\\\`)\n  7. `\\}` - closing bracket inside an interpolation block\n            (it works **only** inside opened interpolation block)\n            to prevent interpolation block from closing\n            (useful to escape records modification)\n\n### Escaping examples\n\n```haskell\n[qm| foo\\nbar  |] -- \"foo\\nbar\"\n[qm| foo\\\\nbar |] -- \"foo\\\\nbar\"\n[qm| foo\\tbar  |] -- \"foo\\tbar\"\n[qm| foo\\\\tbar |] -- \"foo\\\\tbar\"\n[qm| foo\\‣bar  |] -- \"foo\\tbar\"   (`‣` is real tab symbol)\n[qm| foo\\\\‣bar |] -- \"foo\\\\\\tbar\" (`‣` is real tab symbol)\n[qm| foo\\ bar  |] -- \"foo bar\"\n[qm| foo\\\\ bar |] -- \"foo\\\\ bar\"\n\n[qm| foo\\\n     bar  |] -- \"foobar\"\n[qm| foo\\\\\n     bar  |] -- \"foo\\\\bar\"\n\n[qmb| foo\\\n      bar  |] -- \"foobar\"\n[qmb| foo\\\\\n      bar  |] -- \"foo\\\\\\nbar\"\n\n[qm| foo\\bar    |] -- \"foo\\\\bar\"\n[qm| foo\\\\bar   |] -- \"foo\\\\bar\"\n[qm| foo\\\\\\bar  |] -- \"foo\\\\\\\\bar\"\n[qm| foo\\\\\\\\bar |] -- \"foo\\\\\\\\bar\"\n```\n\n## More examples\n\n```haskell\n[qm|   you can escape spaces\n     \\ when you need them    |]\n-- Result: \"you can escape spaces when you need them\"\n```\n\n```haskell\n[qm|\n        indentation and li\n  ne bre\n   aks are i\n       gno\n     red\n|]\n-- Result: \"indentation and line breaks are ignored\"\n```\n\n```haskell\n[qm|  \\  You can escape indentation or\\n\n         line breaks when you need them! \\  |]\n-- Result: \"  You can escape indentation or\\nline breaks when you need them!  \"\n```\n\n```haskell\n[qm| Interpolation blocks can be escaped too: {1+2} \\{3+4} |]\n-- Result: \"Interpolation blocks can be escaped too: 3 {3+4}\"\n```\n\nIf you don't need interpolation - just replace `m` to `n` in quasi-quoter name:\n\n```haskell\n[qm| foo {1+2} |] -- Result: \"foo 3\"\n[qn| foo {1+2} |] -- Result: \"foo {1+2}\"\n\n[qms| foo {1+2} |] -- Result: \"foo 3\"\n[qns| foo {1+2} |] -- Result: \"foo {1+2}\"\n\n[qmb| foo {1+2} |] -- Result: \"foo 3\"\n[qnb| foo {1+2} |] -- Result: \"foo {1+2}\"\n```\n\nThat's how you update some record inside interpolation block\n(you need to escape closing bracket):\n\n```haskell\n{-# LANGUAGE QuasiQuotes #-}\nimport Text.InterpolatedString.QM (qm)\ndata Foo = Foo {bar :: Int, baz :: Int} deriving Show\nmain = let foo = Foo 10 20 in putStrLn [qm| Foo is: {foo {baz = 30\\}} |]\n-- Foo is: Foo {bar = 10, baz = 30}\n```\n\n## Syntax highlighting\n\n### Vim or Neovim\n\n#### \"haskell-vim\" plugin\n\nIf you use [haskell-vim][haskell-vim] plugin (I personally use\n[my own fork][my-haskell-vim-fork] which supports `UnicodeSyntax`) just add to\nyour `.vimrc` or `init.vim` this:\n\n```vim\nfu! s:highlight_haskell_qm_interpolation_blocks()\n  sy match haskellQMStr \".\" containedin=haskellQM contained\n\n  sy region haskellQMBlock matchgroup=haskellDelimiter\n    \\ start=\"\\(^\\|\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\)\\@\u003c={\" end=\"}\"\n    \\ contains=TOP,@Spell containedin=haskellQM contained\n\n  sy region haskellQM matchgroup=haskellTH\n    \\ start=\"\\[qm\\(b\\|s\\)\\?|\" end=\"|\\]\"\n\n  hi def link haskellQMStr String\nendf\n\nau FileType haskell cal s:highlight_haskell_qm_interpolation_blocks()\n```\n\n## Wanna make a contribution or maintain your own fork?\n\nSee [CONTRIBUTING.md][CONTRIBUTING.md].\n\n## Author\n\nViacheslav Lotsmanov\n\nThis library is a heavily rewritten and extended fork of\n[interpolatedstring-perl6][fork-origin]\nwhich was originally created by Audrey Tang.\n\n## License\n\n[The Unlicense][LICENSE]\n\n[haskell-vim]: https://github.com/neovimhaskell/haskell-vim\n[my-haskell-vim-fork]: https://github.com/unclechu/haskell-vim\n[fork-origin]: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs\n\n[CONTRIBUTING.md]: https://github.com/unclechu/haskell-qm-interpolated-string/blob/master/CONTRIBUTING.md\n[LICENSE]: https://github.com/unclechu/haskell-qm-interpolated-string/blob/master/LICENSE\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funclechu%2Fhaskell-qm-interpolated-string","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funclechu%2Fhaskell-qm-interpolated-string","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funclechu%2Fhaskell-qm-interpolated-string/lists"}