summaryrefslogtreecommitdiff
path: root/plugins/xC/fancy-prompt.lua
blob: 0b7000c97892fc19dbe210c8c9a014fabf1c131a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
--
-- fancy-prompt.lua: the fancy multiline prompt you probably want
--
-- Copyright (c) 2016 - 2022, Přemysl Eric Janouch <p@janouch.name>
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--
-- Beware that it is a hack and only goes about 90% of the way, which is why
-- this functionality is only available as a plugin in the first place
-- (well, and also for customizability).
--
-- The biggest problem is that the way we work with Readline is incompatible
-- with multiline prompts, and normal newlines just don't work.  This is being
-- circumvented by using an overflowing single-line prompt with a specially
-- crafted character in the rightmost column that prevents the bar's background
-- from spilling all over the last line.
--
-- There is also a problem with C-r search rendering not clearing out the
-- background but to really fix that mode, we'd have to fully reimplement it
-- since its alternative prompt very often gets overriden by accident anyway.

xC.hook_prompt (function (hook)
	local current = xC.current_buffer
	local chan = current.channel
	local s = current.server

	local bg_color = "255"
	local current_n = 0
	local active = ""
	for i, buffer in ipairs (xC.buffers) do
		if buffer == current then
			current_n = i
		elseif buffer.new_messages_count ~= buffer.new_unimportant_count then
			active = active .. ","
			if buffer.highlighted then
				active = active .. "!"
				bg_color = "224"
			end
			active = active .. i
		end
	end
	local x = current_n .. ":" .. current.name
	if chan and chan.users_len ~= 0 then
		local params = ""
		for mode, param in pairs (chan.param_modes) do
			params = params .. " +" .. mode .. " " .. param
		end
		local modes = chan.no_param_modes .. params:sub (3)
		if modes ~= "" then
			x = x .. "(+" .. modes .. ")"
		end
		x = x .. "{" .. chan.users_len .. "}"
	end
	if current.hide_unimportant then
		x = x .. "<H>"
	end
	if active ~= "" then
		x = x .. " (" .. active:sub (2) .. ")"
	end

	-- Readline 7.0.003 seems to be broken and completely corrupts the prompt.
	-- However 8.0.004 seems to be fine with these, as is libedit 20191231-3.1.
	--x = x:gsub("[\128-\255]", "?")

	-- Align to the terminal's width and apply formatting, including the hack.
	local lines, cols = xC.get_screen_size ()
	local trailing, width = " ", xC.measure (x)
	while cols > 0 and width >= cols do
		x = x:sub (1, utf8.offset (x, -1) - 1)
		trailing, width = ">", xC.measure (x)
	end

	x = "\x01\x1b[0;4;1;38;5;16m\x1b[48;5;" .. bg_color .. "m\x02" ..
		x .. string.rep (" ", cols - width - 1) ..
		"\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02" ..
		trailing .. "\x01\x1b[0;1m\x02"

	local user_prefix = function (chan, user)
		for i, chan_user in ipairs (chan.users) do
			if chan_user.user == user then return chan_user.prefixes end
		end
		return ""
	end
	if s then
		x = x .. "["
		local state = s.state
		if state == "disconnected" or state == "connecting" then
			x = x .. "(" .. state .. ")"
		elseif state ~= "registered" then
			x = x .. "(unregistered)"
		else
			local user, modes = s.user, s.user_mode
			if chan then x = x .. user_prefix (chan, user) end
			x = x .. user.nickname
			if modes ~= "" then x = x .. "(" .. modes .. ")" end
		end
		x = x .. "] "
	else
		-- There needs to be at least one character so that the cursor
		-- doesn't get damaged by our hack in that last column
		x = x .. "> "
	end
	return x
end)