summaryrefslogtreecommitdiff
path: root/plugins/degesch/fancy-prompt.lua
blob: 300801e7d589b719a1fdd1cecb0ea3b2f1ddf1b6 (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
--
-- fancy-prompt.lua: the fancy multiline prompt you probably want
--
-- Copyright (c) 2016, 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.

degesch.hook_prompt (function (hook)
	local current = degesch.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 (degesch.buffers) do
		if buffer == current then
			current_n = i
		elseif buffer.new_messages_count ~= buffer.new_unimportant_count then
			if active ~= "" then active = active .. "," end
			if buffer.highlighted then
				active = active .. "!"
				bg_color = "224"
			end
			active = active .. i
		end
	end
	if active ~= "" then active = "(" .. active .. ")" 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

	local lines, cols = degesch.get_screen_size ()
	x = x .. " " .. active .. string.rep (" ", cols)

	-- Readline seems to be broken and completely corrupts the prompt
	-- (tested on 7.0.003 Archlinux, 7.0-5 Debian buster)
	x = x:gsub("[\128-\255]", "?")

	-- Cut off extra characters and apply formatting, including the hack.
	-- Note that this doesn't count with full-width or zero-width characters.
	local overflow = utf8.offset (x, cols - 1)
	if overflow then x = x:sub (1, overflow) end
	x = "\x01\x1b[0;4;1;38;5;16m\x1b[48;5;" .. bg_color .. "m\x02" ..
		x ..  "\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02 \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)