Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into remove/mastofe
[akkoma] / lib / pleroma / clippy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Clippy do
6 @moduledoc false
7
8 # No software is complete until they have a Clippy implementation.
9 # A ballmer peak _may_ be required to change this module.
10
11 def tip do
12 tips()
13 |> Enum.random()
14 |> puts()
15 end
16
17 def tips do
18 host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])
19
20 [
21 "“πλήρωμα” is “pleroma” in greek",
22 "For an extended Pleroma Clippy Experience, use the “Redmond” themes in Pleroma FE settings",
23 "Staff accounts and MRF policies of Pleroma instances are disclosed on the NodeInfo endpoints for easy transparency!\n
24 - https://catgirl.science/misc/nodeinfo.lua?#{host}
25 - https://fediverse.network/#{host}/federation",
26 "Pleroma can federate to the Dark Web!\n
27 - Tor: https://git.pleroma.social/pleroma/pleroma/wikis/Easy%20Onion%20Federation%20(Tor)
28 - i2p: https://git.pleroma.social/pleroma/pleroma/wikis/I2p%20federation",
29 "Lists of Pleroma instances:\n\n- http://distsn.org/pleroma-instances.html\n- https://fediverse.network/pleroma\n- https://the-federation.info/pleroma",
30 "Pleroma uses the LitePub protocol - https://litepub.social",
31 "To receive more federated posts, subscribe to relays!\n
32 - How-to: https://git.pleroma.social/pleroma/pleroma/wikis/Admin%20tasks#relay-managment
33 - Relays: https://fediverse.network/activityrelay"
34 ]
35 end
36
37 @spec puts(String.t() | [[IO.ANSI.ansicode() | String.t(), ...], ...]) :: nil
38 def puts(text_or_lines) do
39 import IO.ANSI
40
41 lines =
42 if is_binary(text_or_lines) do
43 String.split(text_or_lines, ~r/\n/)
44 else
45 text_or_lines
46 end
47
48 longest_line_size =
49 lines
50 |> Enum.map(&charlist_count_text/1)
51 |> Enum.sort(&>=/2)
52 |> List.first()
53
54 pad_text = longest_line_size
55
56 pad =
57 for(_ <- 1..pad_text, do: "_")
58 |> Enum.join("")
59
60 pad_spaces =
61 for(_ <- 1..pad_text, do: " ")
62 |> Enum.join("")
63
64 spaces = " "
65
66 pre_lines = [
67 " / \\#{spaces} _#{pad}___",
68 " | |#{spaces} / #{pad_spaces} \\"
69 ]
70
71 for l <- pre_lines do
72 IO.puts(l)
73 end
74
75 clippy_lines = [
76 " #{bright()}@ @#{reset()}#{spaces} ",
77 " || ||#{spaces}",
78 " || || <--",
79 " |\\_/| ",
80 " \\___/ "
81 ]
82
83 noclippy_line = " "
84
85 env = %{
86 max_size: pad_text,
87 pad: pad,
88 pad_spaces: pad_spaces,
89 spaces: spaces,
90 pre_lines: pre_lines,
91 noclippy_line: noclippy_line
92 }
93
94 # surrond one/five line clippy with blank lines around to not fuck up the layout
95 #
96 # yes this fix sucks but it's good enough, have you ever seen a release of windows
97 # without some butched features anyway?
98 lines =
99 if length(lines) == 1 or length(lines) == 5 do
100 [""] ++ lines ++ [""]
101 else
102 lines
103 end
104
105 clippy_line(lines, clippy_lines, env)
106 rescue
107 e ->
108 IO.puts("(Clippy crashed, sorry: #{inspect(e)})")
109 IO.puts(text_or_lines)
110 end
111
112 defp clippy_line([line | lines], [prefix | clippy_lines], env) do
113 IO.puts([prefix <> "| ", rpad_line(line, env.max_size)])
114 clippy_line(lines, clippy_lines, env)
115 end
116
117 # more text lines but clippy's complete
118 defp clippy_line([line | lines], [], env) do
119 IO.puts([env.noclippy_line, "| ", rpad_line(line, env.max_size)])
120
121 if lines == [] do
122 IO.puts(env.noclippy_line <> "\\_#{env.pad}___/")
123 end
124
125 clippy_line(lines, [], env)
126 end
127
128 # no more text lines but clippy's not complete
129 defp clippy_line([], [clippy | clippy_lines], env) do
130 if env.pad do
131 IO.puts(clippy <> "\\_#{env.pad}___/")
132 clippy_line([], clippy_lines, %{env | pad: nil})
133 else
134 IO.puts(clippy)
135 clippy_line([], clippy_lines, env)
136 end
137 end
138
139 defp clippy_line(_, _, _) do
140 end
141
142 defp rpad_line(line, max) do
143 pad = max - (charlist_count_text(line) - 2)
144 pads = Enum.join(for(_ <- 1..pad, do: " "))
145 [IO.ANSI.format(line), pads <> " |"]
146 end
147
148 defp charlist_count_text(line) do
149 if is_list(line) do
150 text = Enum.join(Enum.filter(line, &is_binary/1))
151 String.length(text)
152 else
153 String.length(line)
154 end
155 end
156 end