Packages

Yet another static website generator written in Elixir with MD parser (forked from serum)

Current section

Files

Jump to
serum_md lib serum dev_server prompt.ex
Raw

lib/serum/dev_server/prompt.ex

defmodule Serum.DevServer.Prompt do
@moduledoc """
Provides access to the Serum development server command line interface.
"""
import Serum.IOProxy, only: [put_err: 2]
alias Serum.DevServer.CommandHandler
alias Serum.DevServer.Service
alias Serum.GlobalBindings
@type options :: [allow_detach: boolean()]
@type result :: {:ok, :detached} | {:ok, :quitted} | {:error, :noproc}
@service Application.compile_env(:serum_md, :service, Service.GenServer)
@command_handler Application.compile_env(:serum_md, :command_handler, CommandHandler.Impl)
@doc """
Tries to start a Serum development server command line interface.
This function first checks if the server is already running. If the server
is not running, this function returns `{:error, :noproc}` immediately.
Otherwise, it starts a loop which processes commands from the user. If the
user runs the `detach` command, the loop completes and this function returns
`{:ok, :detached}` tuple. If the user runs the `quit` command, the Serum
development server will be stopped, and then this function will return
`{:ok, :quitted}` tuple.
## Options
- `allow_detach`: Controls if users are allowed to detach the command line
interface. Defaults to `true`.
"""
@spec start(options()) :: result()
def start(options \\ []) do
with pid when is_pid(pid) <- Process.whereis(@service),
true <- Process.alive?(pid) do
options2 = Map.merge(%{allow_detach: true}, Map.new(options))
looper(options2)
else
_ -> {:error, :noproc}
end
end
@spec looper(map()) :: result()
defp looper(options) do
prompt = [to_string(@service.port()), "> "]
case run_command(IO.gets(prompt), options) do
:quit -> {:ok, :quitted}
:detach -> {:ok, :detached}
:ok -> looper(options)
end
end
@doc false
@spec run_command(binary() | :eof, map()) :: :ok | :detach | :quit
def run_command(input, options)
def run_command(:eof, options), do: do_run_command("quit", options)
def run_command(cmd, options), do: do_run_command(String.trim(cmd), options)
@spec do_run_command(binary(), map()) :: :ok | :detach | :quit
defp do_run_command(command, options)
defp do_run_command("", _options), do: :ok
defp do_run_command("help", %{allow_detach: false}) do
"""
Available commands are:
help Displays this help message
build Rebuilds the project
open Open the site in a browser
quit Stops the server and quit
"""
|> IO.write()
:ok
end
defp do_run_command("help", %{allow_detach: true}) do
"""
Available commands are:
help Displays this help message
build Rebuilds the project
detach Detaches from this command line interface
while keeping the Serum development server running
open Open the site in a browser
quit Stops the server and quit
"""
|> IO.write()
:ok
end
defp do_run_command("build", _options) do
@service.rebuild()
:ok
end
defp do_run_command("detach", %{allow_detach: false}) do
msg = """
You cannot detach from this command line interface.
Run "quit" to stop the server and quit.
"""
put_err(:warn, String.trim(msg))
end
defp do_run_command("detach", %{allow_detach: true}) do
:detach
end
defp do_run_command("open", _options) do
base_url = GlobalBindings.get(:site)[:base_url]
abs_url = "http://localhost:#{@service.port()}#{base_url}"
case @command_handler.open_url(abs_url) do
:ok -> :ok
_ -> put_err(:warn, "Can't open a browser")
end
end
defp do_run_command("quit", _options) do
Supervisor.stop(Serum.DevServer.Supervisor)
:quit
end
defp do_run_command(_, _options) do
put_err(:warn, "Type \"help\" for the list of available commands.")
end
end