Packages
fnord
0.9.22
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/settings/skills.ex
defmodule Settings.Skills do
@moduledoc """
Manage skill enablement in settings.json.
Schema:
- Global: ["skills"] :: [string]
- Per-project: ["projects", pn, "skills"] :: [string]
## Effective enablement (additive / union)
The effective set of enabled skills is the union of the global list and the
project list (when a project is selected). This matches the semantics used
by `Settings.Frobs`.
All mutations are performed via Settings APIs that provide cross-process locking
and atomic writes.
"""
@type scope :: :global | :project | {:project, String.t()}
@doc """
List enabled skill names for the given scope.
- `:global` reads the top-level `skills` list.
- `:project` reads the selected project's list (or returns `[]` if no project).
- `{:project, name}` reads the named project's list.
This function does not apply override semantics; it reads exactly the requested scope.
"""
@spec list(scope) :: [String.t()]
def list(:global) do
Settings.get(Settings.new(), "skills", [])
|> sanitize_list()
end
def list(:project) do
case Settings.get_selected_project() do
{:ok, pn} -> list({:project, pn})
_ -> []
end
end
def list({:project, pn}) when is_binary(pn) do
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
Map.get(project, "skills", []) |> sanitize_list()
end
@doc """
Enable a skill in the given scope. Idempotent.
"""
@spec enable(scope, String.t()) :: :ok
def enable(scope, name) when is_binary(name) and byte_size(name) > 0 do
names =
list(scope)
|> Kernel.++([name])
|> sanitize_list()
set_list(scope, names)
end
@doc """
Disable a skill in the given scope. Idempotent.
"""
@spec disable(scope, String.t()) :: :ok
def disable(scope, name) when is_binary(name) do
names =
list(scope)
|> Enum.reject(&(&1 == name))
|> sanitize_list()
set_list(scope, names)
end
@doc """
Return the effective set of enabled skills for the current project context.
Additive semantics: the effective set is the union of the global list and
the project list (when a project is selected).
The return is a `MapSet` for convenient membership checks.
"""
@spec effective_enabled() :: MapSet.t(String.t())
def effective_enabled() do
global = list(:global)
project = list(:project)
(global ++ project)
|> MapSet.new()
end
@doc """
Is the given skill enabled in the current project context?
"""
@spec enabled?(String.t()) :: boolean()
def enabled?(name) when is_binary(name) do
MapSet.member?(effective_enabled(), name)
end
# ----------------------------------------------------------------------------
# Internals
# ----------------------------------------------------------------------------
defp sanitize_list(list) when is_list(list) do
list
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
|> Enum.sort()
end
defp sanitize_list(_), do: []
defp set_list(:global, names) when is_list(names) do
Settings.update(Settings.new(), "skills", fn _ -> names end, [])
:ok
end
defp set_list(:project, names) when is_list(names) do
case Settings.get_selected_project() do
{:ok, pn} -> set_list({:project, pn}, names)
_ -> :ok
end
end
defp set_list({:project, pn}, names) when is_list(names) and is_binary(pn) do
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
Settings.set_project_data(settings, pn, Map.put(project, "skills", names))
:ok
end
end