First
[anni] / lib / pleroma / clippy.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 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