Current section
Files
Jump to
Current section
Files
lib/magma/matter/text.ex
defmodule Magma.Matter.Text do
use Magma.Matter, fields: [:type]
alias Magma.{Matter, Concept}
alias Magma.Matter.Text.Section
@type t :: %__MODULE__{}
@type type :: module
@impl true
def artefacts, do: [Magma.Artefacts.TableOfContents]
@sections_section_title "Sections"
def sections_section_title, do: @sections_section_title
@relative_base_path "texts"
@impl true
def relative_base_path(%__MODULE__{} = text),
do: Path.join(@relative_base_path, concept_name(text))
@impl true
def relative_concept_path(%__MODULE__{} = text) do
text
|> relative_base_path()
|> Path.join("#{concept_name(text)}.md")
end
@impl true
def concept_name(%__MODULE__{name: name}), do: name
@impl true
def concept_title(%__MODULE__{name: name}), do: name
@impl true
def default_description(%__MODULE__{name: name}, _) do
"""
What should "#{name}" cover?
"""
|> View.comment()
end
@impl true
def prompt_concept_description_title(%__MODULE__{name: name}) do
"Description of the content to be covered by '#{name}'"
end
@impl true
def context_knowledge(%Concept{subject: %__MODULE__{type: type}} = concept) do
"""
#{super(concept)}
#{Magma.Config.TextType.context_knowledge_transclusion(type)}
"""
|> String.trim_trailing()
end
@impl true
def custom_concept_sections(%Concept{} = concept) do
"""
# #{@sections_section_title}
#{View.comment("Don't remove or edit this section! The results of the generated table of contents will be copied to this place.")}
# Artefact previews
""" <>
Enum.map_join(
Matter.Text.Section.artefacts(),
"\n",
&"- #{concept |> &1.new!() |> View.link_to_preview()}"
)
end
@spec new(binary, keyword) :: {:ok, t()} | {:error, any}
def new(name, attrs \\ []) do
{:ok,
struct(
__MODULE__,
attrs
|> Keyword.put(:name, name)
|> Keyword.put_new(:type, Magma.Matter.Texts.Generic)
)}
end
def new!(name, attrs \\ []) do
case new(name, attrs) do
{:ok, matter} -> matter
{:error, error} -> raise error
end
end
@doc false
def request_prompt_task_template_bindings(%Concept{subject: %__MODULE__{} = text}) do
[
text: text,
section: nil
]
end
def request_prompt_task_template_bindings(%Concept{subject: %Section{} = section}) do
[
text: section.main_text,
section: section
]
end
@impl true
def extract_from_metadata(document_name, _document_title, metadata) do
{magma_matter_text_type, remaining} = Map.pop(metadata, :magma_matter_text_type)
cond do
!magma_matter_text_type ->
{:error, "magma_matter_text_type missing in #{document_name}"}
text_type = type(magma_matter_text_type) ->
with {:ok, matter} <- new(document_name, type: text_type) do
{:ok, matter, remaining}
end
true ->
{:error, "invalid magma_matter_text_type: #{magma_matter_text_type}"}
end
end
def render_front_matter(%__MODULE__{} = text) do
"""
#{super(text)}
magma_matter_text_type: #{Magma.Matter.Text.type_name(text.type)}
"""
|> String.trim_trailing()
end
@doc """
Returns the text type name for the given text module.
## Example
iex> Magma.Matter.Text.type_name(Magma.Matter.Texts.UserGuide)
"UserGuide"
iex> Magma.Matter.Text.type_name(Magma.Matter.Texts.Generic)
"Generic"
iex> Magma.Matter.Text.type_name(Magma.Vault)
** (RuntimeError) Invalid Magma.Matter.Text type: Magma.Vault
iex> Magma.Matter.Text.type_name(NonExisting)
** (RuntimeError) Invalid Magma.Matter.Text type: NonExisting
"""
def type_name(type, validate \\ true) do
if not validate or type?(type) do
case Module.split(type) do
["Magma", "Matter", "Texts" | name_parts] -> Enum.join(name_parts, ".")
_ -> raise "Invalid Magma.Matter.Text type: #{inspect(type)}"
end
else
raise "Invalid Magma.Matter.Text type: #{inspect(type)}"
end
end
@doc """
Returns the text type module for the given string.
## Example
iex> Magma.Matter.Text.type("UserGuide")
Magma.Matter.Texts.UserGuide
iex> Magma.Matter.Text.type("Generic")
Magma.Matter.Texts.Generic
iex> Magma.Matter.Text.type("Vault")
nil
iex> Magma.Matter.Text.type("NonExisting")
nil
"""
def type(string, validate \\ true) when is_binary(string) do
module = Module.concat(Magma.Matter.Texts, string)
if not validate or type?(module) do
module
end
end
def type?(module) do
module in Magma.Config.text_types()
end
end