<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Friday, April 09, 2010, 3:17 PM -->
<!-- MuClient version 4.51 -->

<!-- Plugin "channel_history" generated by Plugin Wizard -->

<muclient>
<plugin
   name="channel_history"
   author="Tyler S, Oriol G, and Weyoun"
   id="6000a4c6f0e71d31fecf523d"
   language="Lua"
   purpose="Allows reading of messages sorted into categories with hotkeys"
   date_written="2010-04-09 15:14:12"
   requires="4.51"
   version="2.2"
save_state="y"
   >
<description trim="y">
<![CDATA[
The only alias you should need is history_add. Its syntax is:
history_add category=message

Accelerator keys:
alt+right and alt+left - next and previous category buffer
shift+alt+right and left  - move buffer.
alt+Delete - delete a buffer.
alt+1 through alt+0 - read 1st to 10th latest message in buffer. pressing one of these keys twice within 0.5 seconds will copy the message to the clipboard, and 3 times will paste it into the command window.
Alt+up or Alt+ Down Arrow - move through messages in the current buffer. The latest messages are at the bottom of the buffer.
Alt + Pageup or Alt + PageDown: move up or down 10 messages in the current buffer.
Alt + Home or Alt + End: Move up or down 2000 messages in the current buffer
Alt + Space: Repeat currently selected buffer item
Alt + Shift + Space: Copy selected buffer item to clipboard
Alt + Enter: Open URLs in the current buffer item if any, otherwise open the world configuration dialog
Alt + Shift + Enter: Copy all items in current buffer to an output window
Alt + Shift + T: Toggle hearing a relative time announcement after each message, such as 2 minutes ago.
]]>
</description>

</plugin>


<!--  Get our standard constants -->

<include name="constants.lua"/>

<!--  Aliases  -->

<aliases>
  <alias
   script="history_delete"
   match="^history_delete"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>

  <alias
   script="category_move"
   match="^history_move (\w+)"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>

  <alias
   script="history_add"
   match="^history_add (\w[\w ]*)=(.*)"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="ttstoggle"
   match="config tts"
   enabled="y"
   omit_from_command_history="y"
keep_evaluating="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_get"
   match="^history_get (\d+)$"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_link"
   match="^history_get_link"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   regexp="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_catprev"
   match="history_catprev"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_catnext"
   match="history_catnext"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_msgprev"
   match="^history_msgprev (\d+)$"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   regexp="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_msgnext"
   match="^history_msgnext (\d+)$"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   regexp="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_msgcopy"
   match="history_msgcopy"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   script="history_notepad"
   match="history_notepad"
   enabled="y"
   omit_from_command_history="y"
   omit_from_log="y"
   omit_from_output="y"
   sequence="100"
  >
  </alias>
  <alias
   match="^(|history\_)timestamps?$"
   enabled="y"
   regexp="y"
   send_to="12"
   ignore_case="y"
   sequence="100"
  >
  <send>if timestamps==true then
timestamps=false
SetVariable("timestamps", "false")
Execute("tts_interrupt Timestamps will no longer be spoken after messages.")
else
timestamps=true
SetVariable("timestamps", "true")
Execute("tts_interrupt You will now hear an approximate time after every message.")
end</send>
  </alias>
    <alias
   enabled="y"
   match="^chist changes?(?P&lt;num&gt; \d+)?$"
   send_to="12"
   group="help"
   regexp="y"
   sequence="100"
  >
  <send>
  require "changelog"
  require "var"
  
  display_changelog(nil, "%0", {num="%&lt;num&gt;", lines=var.changelog})
  
  </send>
  </alias>
 
</aliases>

<!-- Variables -->

<variables>
  <variable name="changelog">Channel History Change log:

v2.2 - Jun 14, 20
Changes from Xera
Fix bug in new url opening feature where it was preventing alt+enter from opening world properties.
  
v2.1 - Mar 30, 20
Changes from Ivey
Updated the show info message to include all the current commands.
Fixed some bugs
Added larger buffer limit
Support for opening urls in the current item (Alt+Enter)

Changes from Xera
Added support for displaying a change log
</variable>
</variables>

<!-- Script -->

<script>
<![CDATA[
modes = {} -- for keyboard states
messages = {}
indices = {}
current_category = 0 -- not set yet
categories = {}
if not GetVariable("timestamps") then
timestamps=true
DoAfterSpecial(30, "Note('You can now toggle off the new relative time announcements in channel history. Press alt+shift+t to turn it on or off. Alternatively, you can just type timestamp.')", 14)
SetVariable("timestamps", "true")
elseif GetVariable("timestamps") == "false" then
timestamps=false
Note("Channel history timestamps are disabled.")
else
timestamps=true
Note("Channel history timestamps are enabled.")
end

-- set up accelerators
for i = 1, 9 do
Accelerator("alt + " .. i, "history_get " .. i)
end
Accelerator("alt + 0", "history_get 10") -- 10 is a special case
Accelerator("alt + right", "history_catnext")
Accelerator("alt + left", "history_catprev")
Accelerator("alt + down", "history_msgnext 1")
Accelerator("alt + up", "history_msgprev 1")
Accelerator("alt + pagedown", "history_msgnext 10")
Accelerator("alt + pageup", "history_msgprev 10")
Accelerator("alt + end", "history_msgnext 2000")
Accelerator("alt + home", "history_msgprev 2000")
Accelerator("shift+alt + right", "history_move right")
Accelerator("shift+alt + left", "history_move left")
Accelerator("alt+shift+delete","history_delete")
Accelerator("alt + space", "history_msgprev 0")
Accelerator("alt+shift+space","history_msgcopy")
Accelerator("alt+shift+enter","history_notepad")
Accelerator("alt+enter","history_get_link")
Accelerator("alt+shift+t","timestamps")

function history_delete(n,l,w)
 if #categories == 0 then
  say("no categories")
  return
 end
 if current_category == 0 then
  say("No category selected.")
  return
 end
 messages[categories[current_category]] = nil
 indices[categories[current_category]] = nil
 table.remove(categories, current_category)
 if current_category > #categories then
  current_category = 1
 end
 if #categories > 0 then
  say(categories[current_category])
 else
  say("no more categories.")
-- Prevent other code from crashing:
categories = { }
current_category = 0
 end
end

function category_move(name, line, w)
 if #categories == 0 then
  say("no categories")
  return
 end
 if current_category == 0 then
  say("No category selected.")
  return
 end
 name = categories[current_category]
 table.remove(categories,current_category)
 if w[1]=="right" then
  current_category = current_category + 1
  if current_category > #categories + 1 then
   current_category = 2
  end
 else
  current_category = current_category - 1
  if current_category < 1 then
   current_category = #categories
  end
 end
 table.insert(categories, current_category, name)
 say("moved.")
end

function OnPluginInstall()
 --SetVariable("tts",GetPluginVariable("553a883096da345ce6897740","tts"))
 SetVariable("tts","1")
end

function ttstoggle(n,l,w)
 SetVariable("tts",GetPluginVariable("553a883096da345ce6897740","tts"))
end

function history_add(name, line, wc)
 local cat, msg = wc[1], wc[2]
 if messages[cat] == nil then
  messages[cat] = {}
  indices[cat] = 0
  table.insert(categories, cat)
 end
 table.insert(messages[cat], {["message"]=msg,["time"]=os.clock()})
 -- if we go over 100 items, remove the oldest one
 if #messages[cat] > 100000 then
  table.remove(messages[cat], 1)
  if indices[cat] > 1 then
   indices[cat] = indices[cat] - 1
  end
 end
end

-- helper function to say stuff
function say(x) 
 if(GetVariable("tts")=="1") then
  Execute("tts_interrupt " .. x)
 else
  Note(x)
 end
end

function history_get(name, line, wc)
 local str = ""
 if current_category == 0 and #categories == 0 then
  say("No categories")
  return
 elseif current_category == 0 and #categories > 0 then
  for i, result in ipairs(categories) do
   if categories[i] == "all" then
    current_category = i
   end
  end
  if current_category > 0 then
   str = str .. "switching to all."
  else
   str = str .. "switching to " .. categories[1] .. ". Use alt left and right arrows to change."
   current_category = 1
  end
 end
 local item = tonumber(wc[1])
 if #messages[categories[current_category]] < item then
  say("no message")
  return
 end

 -- now that all that's out of the way, we can start our real code which should always succeed.
 local timeout = 0.5 -- in seconds
 if modes[item] == nil then
  modes[item] = {os.clock(), 1}
 elseif os.clock()-modes[item][1] >= timeout then
  modes[item][1] = os.clock()
  modes[item][2] = 1
 else
  modes[item][1] = os.clock()
  modes[item][2] = modes[item][2] + 1
 end
 if modes[item][2] > 3 then
  modes[item][2] = 3
 end

 local real_item = #messages[categories[current_category]] + 1 - item
 if modes[item][2] == 1 then
  sayMsg(str, messages[categories[current_category]][real_item])
 elseif modes[item][2] == 2 then
  SetClipboard(messages[categories[current_category]][real_item]["message"])
  say("copied")
 elseif modes[item][2] == 3 then
  PasteCommand(messages[categories[current_category]][real_item]["message"])
  say("pasted")
 end
end

function sayMsg(str,m)
saythis=str .. " " .. m["message"]
if timestamps==true then
local lastchar=string.byte(m["message"]:sub(-1))
--print(lastchar)
if (lastchar>=49 and lastchar<=57) or (lastchar>=65 and lastchar<=91) or (lastchar>=97 and lastchar<=123) then
saythis=saythis.."."
end
saythis=saythis.." "..calculateRelativeTime(os.clock()-m["time"])
end
say(saythis)
end
function calculateRelativeTime(t)
if t<1 then
return "just now"
end
if t>=1 and t<60 then
return math.ceil(t).." seconds ago"
end
if t>=60 and t<3600 then
local min=math.floor(t/60)
local sec=math.ceil(math.fmod(t,60))
return min.." minutes "..sec.." seconds ago"
end
if t>=3600 and t<86400 then -- amount of seconds in a day.
local hr=math.floor(t/3600)
local min=math.floor((t%3600)/60)
return hr.." hours "..min.." minutes ago"
end
if t>86400 then
local days=math.floor(t/86400)
local hr=math.floor((t-(86400*days))/3600)
local min=math.floor(((t-((86400*days)+(3600*hr)))/60))
return days.." days, "..hr.." hours, and "..min.." minutes ago"
end

return ""
--return os.clock()-t
end
function history_catnext(name, line, wc)
 if #categories == 0 then
  say("no categories")
  return
 end
 current_category = current_category + 1
 if current_category > #categories then
  current_category = 1
 end
if indices[categories[current_category]]==0 then indices[categories[current_category]]=1 end
 say(categories[current_category] ..": "..indices[categories[current_category]] .. " of " .. #messages[categories[current_category]])
end

function history_catprev(name, line, wc)
 if #categories == 0 then
  say("no categories")
  return
 end
 current_category = current_category - 1
 if current_category < 1 then
  current_category = #categories
 end
if indices[categories[current_category]]==0 then indices[categories[current_category]]=1 end
 say(categories[current_category] ..": "..indices[categories[current_category]] .. " of " .. #messages[categories[current_category]])
end

function history_msgnext(name, line, wc)
 local skip = tonumber(wc[1])
 local str = ""
 if #categories == 0 then
  say("no categories")
  return
 end
 if current_category == 0 then
  say("No category selected.")
  return
 end
 if indices[categories[current_category]] == 0 then
  indices[categories[current_category]] = #messages[categories[current_category]]
 end
 if indices[categories[current_category]] + skip > #messages[categories[current_category]] then
  indices[categories[current_category]] = #messages[categories[current_category]]
  str = str .. "Bottom: "
 else
  indices[categories[current_category]] = indices[categories[current_category]] + skip
 end
 sayMsg(str, messages[categories[current_category]][indices[categories[current_category]]])
end

function history_msgprev(name, line, wc)
 local skip = tonumber(wc[1])
 local str = ""
 if #categories == 0 then
  say("no categories")
  return
 end
 if current_category == 0 then
  say("No category selected.")
  return
 end
 if indices[categories[current_category]] == 0 then
  indices[categories[current_category]] = #messages[categories[current_category]]
 end
 if indices[categories[current_category]] - skip < 1 then
  indices[categories[current_category]] = 1
  str = str .. "Top: "
 else
  indices[categories[current_category]] = indices[categories[current_category]] - skip
 end
 sayMsg(str, messages[categories[current_category]][indices[categories[current_category]]])
end

function history_link(name, line, wc)
 if #categories == 0 then
  say("no categories")
  say("opening world configuration")
  DoAfterSpecial(1,"DoCommand('preferences')",12)
  return
 end -- if
  
 if current_category == 0 then
  say("No category selected.")
  say("opening world configuration")
  DoAfterSpecial(1,"DoCommand('preferences')",12)
  return
 end -- if
 
 if indices[categories[current_category]] == 0 then
  indices[categories[current_category]] = #messages[categories[current_category]]
 end -- if
 
 local hmm=(messages[categories[current_category]][indices[categories[current_category]]]["message"])
  links={}
  re=rex.new("(http|ftp|https)://([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%:/~+#-]*[\\w@?^=%/~+#-])?")
 n=re:gmatch(hmm,function(m, t)
  table.insert(links,m)
 end)
 
 if #links==0 then
  say("no links, opening world configuration")
  DoAfterSpecial(1,"DoCommand('preferences')",12)
 end -- if
 
 if #links==1 then
  say("Opening URL: "..links[1])
  OpenBrowser(links[1])
 end -- if
 
 if #links>1 then
  url=utils.listbox("","Select URL",links,1)
  if url then
   OpenBrowser(links[url])
  end -- if
 end -- if
end -- function

function history_msgcopy(name, line, wc)
 if #categories == 0 then
  say("no categories")
  return
 end
 if current_category == 0 then
  say("No category selected.")
  return
 end
 if indices[categories[current_category]] == 0 then
  indices[categories[current_category]] = #messages[categories[current_category]]
 end
 SetClipboard(messages[categories[current_category]][indices[categories[current_category]]]["message"])
 say("copied")
end
function history_notepad()
if #categories == 0 then
say("no categories")
return
end
if current_category == 0 then
say("No category selected.")
return
end
np = categories[current_category]
local nptext="Showing "..#messages[categories[current_category]].." messages:\r\n"
for i = 1, #messages[categories[current_category]] do
if timestamps==true then
nptext = nptext.. "[" .. os.date("%c", (os.time()-os.clock()+messages[categories[current_category]][i]["time"])) .. "] " .. messages[categories[current_category]][i]["message"].."\r\n"
else
nptext = nptext..messages[categories[current_category]][i]["message"].."\r\n"
end
end
SendToNotepad(np, nptext)
 NotepadReadOnly(np, true)
 ActivateNotepad(np)
 end

]]>
</script>
</muclient>
