]> git.gir.st - ircpipe.git/blob - contrib/highlight
provide a tool to highlight irc protocol messages
[ircpipe.git] / contrib / highlight
1 #!/usr/bin/python3
2
3 import sys
4
5 def parse(line): #-> [nick, user, host], command, arguments
6 prefix, params = b"", []
7 command, arguments = None, []
8 nick, user, host = None, None, None
9
10 line = line.rstrip(b"\r\n")
11 # handle prefix:
12 if line.startswith(b":"):
13 prefix, line = line.split(b" ", 1)
14 # handle command and arguments:
15 while b" " in line and not line.startswith(b":"):
16 word, line = line.split(b" ", 1)
17 params += [word]
18 # handle final parameter:
19 params += [line.removeprefix(b":")]
20
21 if params:
22 # note: command may also be a numeric reply
23 command, *arguments = params
24
25 if b"!" in prefix and b"@" in prefix:
26 nick, rest = prefix.removeprefix(b":").split(b"!", 1)
27 user, host = rest.split(b"@", 1)
28 elif prefix: # server
29 host = prefix.removeprefix(b":")
30
31 return [nick, user, host], command, arguments
32
33 DIM = b"\033[0;2m"
34 BOLD = b"\033[0;1m"
35 RESET = b"\033[0m"
36 REV = b"\033[0;7m"
37
38 def say(*args):
39 sys.stdout.buffer.write(b"".join(args)+b"\n")
40 sys.stdout.buffer.flush()
41
42 def findall(needle, haystack):
43 if not needle: return []
44 spans, offset, length = [], 0, len(needle)
45 nickchars = (
46 br"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47 br"abcdefghijklmnopqrstuvwxyz"
48 br"0123456789-[\]^_`{|}")
49
50 while offset < len(haystack):
51 try:
52 offset = haystack.index(needle, offset)
53 # check for a word boundary before and after nick:
54 if (offset==0 or haystack[offset-1] not in nickchars) \
55 and (offset+length==len(haystack) or haystack[offset+length] not in nickchars):
56 spans += [(offset, length)]
57 offset += length
58 except ValueError as e:
59 break # no more matches
60 return spans
61
62 myself = None
63 for line in sys.stdin.buffer:
64 [nick, user, host], command, arguments = parse(line)
65
66 if command in (b"PRIVMSG", b"NOTICE") and len(arguments) == 2 and nick:
67 chan, msg = arguments
68 nick_start = len(b":")
69 nick_end = nick_start+len(nick)
70 cmd_start = nick_end+len(b"!")+len(user)+len(b"@")+len(host)+len(b" ")
71 cmd_end = cmd_start+len(command)
72 chan_start = cmd_end+len(b" ")
73 chan_end = chan_start+len(chan)
74 msg_start = chan_end+len(b" ")
75 msg_end = msg_start+len(msg)
76 if line[msg_start] == ord(':'):
77 msg_start +=1
78 msg_end +=1
79
80 hi_msg = line[msg_start:msg_end]
81 for s,l in reversed(findall(myself, hi_msg)):
82 hi_msg = hi_msg[:s] + REV + hi_msg[s:s+l] + RESET + hi_msg[s+l:]
83
84 # maybe todo:
85 # - support mIRC highlighting (colors, bold, etc)
86 # https://modern.ircdocs.horse/formatting.html
87 # including \x01ACTION privmsg prefix
88 # - highlight own nick and/or user-def'd strings
89
90 say(
91 DIM, line[:nick_start],
92 BOLD, line[nick_start:nick_end],
93 DIM, line[nick_end:chan_start],
94 BOLD, line[chan_start:chan_end],
95 DIM, line[chan_end:msg_start],
96 RESET, hi_msg,
97 REV, line[msg_end:].rstrip(b"\r\n"),
98 RESET)
99 elif command in (b"PING", b"PONG"):
100 pass # hide (could also do "JOIN", "QUIT", motd, names, ...)
101 else:
102 if command == b"001" and arguments:
103 myself = arguments[0] # store own username for later highlighting it
104 say(
105 DIM, line.rstrip(b"\r\n"),
106 RESET)
Imprint / Impressum