lib/gemtext.ex

defmodule Gemtext do
  @moduledoc """
  Gemtext is a lightweight markup language for the Gemini protocol.

  This module can parse a "gemtext" into a list of nodes or render the samne
  list of nodes into the original "gemtext".

  ### Gemtext cheatsheet
  ___

  * Long lines get wrapped by the client to fit the screen
  * Short lines *don't* get joined together
  * Write paragraphs as single long lines
  * Blank lines are rendered verbatim
  * lines which start with `` ``` `` will cause clients to toggle in and out of
    ordinary rendering mode and preformatted mode. In preformatted mode,
    Gemtext syntax is ignored so links etc. will not be rendered, and text
    will appear in a monospace font.


  ### Core types
  ___

  where


  * <...> is a token
  * [...] is an optional element
  * [<...>] means zero or one
  * <...>* means zero or more
  * <...>+ means one or more
  * <whitespace> is a space or a tab
  * <eol> is one of the `eol` sequences `\\r`, `\\n` or `\\r\\n`
  * <url> is either an absolute or a relative url.


  #### Heading

  ```text
  #[<whitespace>]Heading title<eol>
  ```

  There are three levels of heading:

  ```text
  # Heading

  ## Sub-heading

  ### Sub-subheading
  ```

  #### List item

  There's only one kind of list and you can't nest them:

  ```text
  *[<whitespace>]List item text<eol>
  ```

  ```text
  * Mercury
  * Gemini
  * Apollo
  ```

  #### Blockquote

  ```text
  >[<whitespace>]Famous quote here<eol>
  ```

  ```text
  > I hope so for your sake, Commander. The Emperor is not as forgiving as I am.
  ```

  #### Link

  ```text
  =><whitespace>*<url>[<whitespace><link name>]
  ```

  ```text
  => /logout
  => / Go home
  => gemini://gemini.circumlunar.space Project Gemini
  ```

  #### Preformatted text

  ```text
  ```<eol>[<whitespace>*<text_type><eol>](<line of text><eol>)+```
  ```

  ``````text
  ```elixir
  iex> "Elixir" |> String.graphemes() |> Enum.frequencies()
  %{"E" => 1, "i" => 2, "l" => 1, "r" => 1, "x" => 1}
  ```
  ``````

  #### Text

  ```text
  everyting until<eol>
  ```

  ```text
  This is normal text Line 1
  This is normal text Line 2
  This is a robot emoji 🤖
  ```

  """

  @type gemtext_blocks :: __MODULE__.Parser.gemtext_blocks()

  @spec parse(String.t()) :: gemtext_blocks()
  defdelegate parse(gemtext), to: Gemtext.Parser

  @spec render(gemtext_blocks()) :: String.t()
  defdelegate render(items), to: Gemtext.Renderer
end