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