handlers.lua (5431B)
1 local action = require( "action" ) 2 local alias = require( "alias" ) 3 local intercept = require( "intercept" ) 4 local gag = require( "gag" ) 5 local macro = require( "macro" ) 6 local sub = require( "sub" ) 7 local interval = require( "interval" ) 8 9 local lpeg = require( "lpeg" ) 10 11 local GA = "\255\249" 12 13 local bold = false 14 local fg = 7 15 local bg = 0 16 17 local lastWasChat = false 18 local lastWasGA = false 19 20 local receiving = false 21 local showInput = true 22 23 local dataBuffer = "" 24 local pendingInputs = { } 25 26 local function echoOn() 27 showInput = true 28 29 return "" 30 end 31 32 local function echoOff() 33 showInput = false 34 35 return "" 36 end 37 38 local function setFG( colour ) 39 return function() 40 fg = colour 41 end 42 end 43 44 local function setBG( colour ) 45 return function() 46 bg = colour 47 end 48 end 49 50 local Escapes = { 51 m = { 52 [ "0" ] = function() 53 bold = false 54 fg = 7 55 bg = 0 56 end, 57 58 [ "1" ] = function() 59 bold = true 60 end, 61 62 [ "30" ] = setFG( 0 ), 63 [ "31" ] = setFG( 1 ), 64 [ "32" ] = setFG( 2 ), 65 [ "33" ] = setFG( 3 ), 66 [ "34" ] = setFG( 4 ), 67 [ "35" ] = setFG( 5 ), 68 [ "36" ] = setFG( 6 ), 69 [ "37" ] = setFG( 7 ), 70 71 [ "40" ] = setBG( 0 ), 72 [ "41" ] = setBG( 1 ), 73 [ "42" ] = setBG( 2 ), 74 [ "43" ] = setBG( 3 ), 75 [ "44" ] = setBG( 4 ), 76 [ "45" ] = setBG( 5 ), 77 [ "46" ] = setBG( 6 ), 78 [ "47" ] = setBG( 7 ), 79 }, 80 } 81 82 local function printPendingInputs() 83 if lastWasChat then 84 mud.newlineMain() 85 86 lastWasChat = false 87 end 88 89 for i = 1, #pendingInputs do 90 mud.printr( pendingInputs[ i ] ) 91 92 lastWasGA = false 93 end 94 95 pendingInputs = { } 96 end 97 98 local function handleChat( message ) 99 lastWasChat = true 100 lastWasGA = false 101 102 if not message then 103 return 104 end 105 106 local oldFG = fg 107 local oldBG = bg 108 local oldBold = bold 109 110 fg = 1 111 bg = 0 112 bold = true 113 114 local noAnsi = message:gsub( "\27%[[%d;]*%a", "" ) 115 116 action.doChatPreActions( noAnsi ) 117 action.doChatAnsiPreActions( message ) 118 119 mud.newlineMain() 120 mud.newlineChat() 121 122 for line, newLine in message:gmatch( "([^\n]*)(\n?)" ) do 123 for text, opts, escape in ( line .. "\27[m" ):gmatch( "(.-)\27%[([%d;]*)(%a)" ) do 124 if text ~= "" then 125 mud.printMain( text, fg, bg, bold ) 126 mud.printChat( text, fg, bg, bold ) 127 end 128 129 for opt in opts:gmatch( "([^;]+)" ) do 130 if Escapes[ escape ][ opt ] then 131 Escapes[ escape ][ opt ]() 132 end 133 end 134 end 135 136 if newLine == "\n" then 137 mud.newlineMain() 138 mud.newlineChat() 139 end 140 end 141 142 action.doChatActions( noAnsi ) 143 action.doChatAnsiActions( message ) 144 145 fg = oldFG 146 bg = oldBG 147 bold = oldBold 148 end 149 150 local function handleData( data ) 151 receiving = true 152 153 dataBuffer = dataBuffer .. data 154 155 -- TODO: this sucks! 156 -- can insert newlines in random places if we receive a GA followed by partial data 157 if data:match( GA ) then 158 dataBuffer = dataBuffer:gsub( "\r", "" ) 159 160 dataBuffer = dataBuffer:gsub( "\255\252\1", echoOn ) 161 dataBuffer = dataBuffer:gsub( "\255\251\1", echoOff ) 162 163 dataBuffer = dataBuffer:gsub( "\255\253\24", "" ) 164 dataBuffer = dataBuffer:gsub( "\255\253\31", "" ) 165 dataBuffer = dataBuffer:gsub( "\255\253\34", "" ) 166 167 dataBuffer = dataBuffer .. "\n" 168 169 for line in dataBuffer:gmatch( "([^\n]*)\n" ) do 170 if lastWasGA then 171 if line ~= "" then 172 mud.newlineMain() 173 end 174 175 lastWasGA = false 176 end 177 178 if lastWasChat then 179 mud.newlineMain() 180 181 lastWasChat = false 182 end 183 184 local clean, subs = line:gsub( GA, "" ) 185 local hasGA = subs ~= 0 186 187 local noAnsi = clean:gsub( "\27%[%d*%a", "" ) 188 189 local gagged = gag.doGags( noAnsi ) or gag.doAnsiGags( clean ) 190 191 action.doPreActions( noAnsi ) 192 action.doAnsiPreActions( clean ) 193 194 local subbed = sub.doSubs( clean ) 195 196 for text, opts, escape in ( subbed .. "\27[m" ):gmatch( "(.-)\27%[([%d;]*)(%a)" ) do 197 if text ~= "" and not gagged then 198 mud.printMain( text, fg, bg, bold ) 199 end 200 201 for opt in opts:gmatch( "([^;]+)" ) do 202 if Escapes[ escape ] and Escapes[ escape ][ opt ] then 203 Escapes[ escape ][ opt ]() 204 end 205 end 206 end 207 208 if hasGA then 209 lastWasGA = true 210 printPendingInputs() 211 else 212 if not gagged then 213 mud.newlineMain() 214 end 215 end 216 217 action.doActions( noAnsi ) 218 action.doAnsiActions( clean ) 219 end 220 221 dataBuffer = "" 222 receiving = false 223 end 224 end 225 226 local function handleCommand( input, hide ) 227 if not alias.doAlias( input ) then 228 if not mud.connected then 229 mud.print( "\n#s> You're not connected..." ) 230 231 return 232 end 233 234 intercept.doIntercept( input ) 235 236 if not hide and input ~= "" then 237 local toShow = ( showInput and input or ( "*" ):rep( input:len() ) ) .. "\n" 238 239 if receiving then 240 table.insert( pendingInputs, toShow ) 241 else 242 if lastWasChat then 243 mud.newlineMain() 244 245 lastWasChat = false 246 end 247 248 lastWasGA = false 249 250 mud.printr( toShow ) 251 end 252 end 253 254 mud.send( input .. "\n" ) 255 end 256 end 257 258 local function handleInput( input, display ) 259 mud.last_human_input_time = mud.now() 260 261 for command in ( input .. ";" ):gmatch( "([^;]*);" ) do 262 handleCommand( command, display ) 263 end 264 end 265 266 mud.input = handleInput 267 268 local function handleMacro( key, shift, ctrl, alt ) 269 mud.last_human_input_time = mud.now() 270 271 if shift then 272 key = "s" .. key 273 end 274 275 if ctrl then 276 key = "c" .. key 277 end 278 279 if alt then 280 key = "a" .. key 281 end 282 283 macro.doMacro( key ) 284 end 285 286 local function handleClose() 287 mud.event( "shutdown" ) 288 end 289 290 return { 291 data = handleData, 292 chat = handleChat, 293 input = handleInput, 294 macro = handleMacro, 295 interval = interval.doIntervals, 296 socket = handleSocketData, 297 close = handleClose, 298 }