From 15e330500187ba2499c0570d21e5b16e98de0f82 Mon Sep 17 00:00:00 2001
From: Stephen Dranger <dranger@gmail.com>
Date: Tue, 12 Apr 2011 18:54:01 -0500
Subject: [PATCH] halfwya;

---
 CHANGELOG.mkdn |  1 +
 convo.py       | 10 ++++++++++
 parsetools.py  | 18 +++++++++++++++++-
 pesterchum.js  |  2 +-
 4 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.mkdn b/CHANGELOG.mkdn
index f3f52da..239aeab 100644
--- a/CHANGELOG.mkdn
+++ b/CHANGELOG.mkdn
@@ -17,6 +17,7 @@ CHANGELOG
 * Logviewer - Kiooeht [evacipatedBox]
 * Quirk ordering - alGore
 * # of users in a memo - alGore
+* @links to users - illuminatedwax [ghostDunk]
 
 BUG FIXES:
 * mixer bug fixed
diff --git a/convo.py b/convo.py
index 4c2b02b..6f5ad20 100644
--- a/convo.py
+++ b/convo.py
@@ -304,6 +304,16 @@ class PesterText(QtGui.QTextEdit):
         if url != "":
             if url[0] == "#" and url != "#pesterchum":
                 self.parent().mainwindow.showMemos(url[1:])
+            elif url[0] == "@":
+                handle = unicode(url[1:])
+                mw = self.parent().mainwindow
+                matchingChums = [c for c in mw.chumList.chums if c.handle == handle]
+                if len(matchingChums) > 0:
+                    mood = matchingChums[0].mood
+                else:
+                    mood = Mood(0)
+                chum = PesterProfile(handle, mood=mood, chumdb=mw.chumdb)
+                mw.newConversation(chum)
             else:
                 QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
         QtGui.QTextEdit.mousePressEvent(self, event)
diff --git a/parsetools.py b/parsetools.py
index a495c93..500a143 100644
--- a/parsetools.py
+++ b/parsetools.py
@@ -11,6 +11,7 @@ _ctag_end = re.compile(r'(?i)</c>')
 _ctag_rgb = re.compile(r'\d+,\d+,\d+')
 _urlre = re.compile(r"(?i)https?://[^\s]+")
 _memore = re.compile(r"(\s|^)(#[A-Za-z0-9_]+)")
+_handlere = re.compile(r"(\s|^)(@[A-Za-z0-9_]+)")
 _imgre = re.compile(r"""(?i)<img src=['"](\S+)['"]\s*/>""")
 _mecmdre = re.compile(r"^(/me|PESTERCHUM:ME)(\S*)")
 
@@ -109,6 +110,16 @@ class memolex(object):
             return "%s<a href='%s'>%s</a>" % (self.space, self.channel, self.channel)
         else:
             return self.string
+class chumhandlelex(object):
+    def __init__(self, string, space, handle):
+        self.string = string
+        self.space = space
+        self.handle = handle
+    def convert(self, format):
+        if format == "html":
+            return "%s<a href='%s'>%s</a>" % (self.space, self.handle, self.handle)
+        else:
+            return self.string
 class smiley(object):
     def __init__(self, string):
         self.string = string
@@ -129,6 +140,7 @@ def lexMessage(string):
                (colorBegin, _ctag_begin), (colorBegin, _gtag_begin),
                (colorEnd, _ctag_end), (imagelink, _imgre),
                (hyperlink, _urlre), (memolex, _memore),
+               (chumhandlelex, _handlere),
                (smiley, _smilere)]
 
     string = unicode(string)
@@ -188,7 +200,11 @@ def splitMessage(msg, format="ctag"):
         if type(o) is colorBegin:
             cbegintags.append(o)
         elif type(o) is colorEnd:
-            cbegintags.pop()
+            print len(cbegintags)
+            try:
+                cbegintags.pop()
+            except IndexError:
+                print len(cbegintags)
         # yeah normally i'd do binary search but im lazy
         msglen = len(convertTags(okmsg, format)) + 4*(len(cbegintags))
         if msglen > 400:
diff --git a/pesterchum.js b/pesterchum.js
index e255fa9..4fd381c 100644
--- a/pesterchum.js
+++ b/pesterchum.js
@@ -1 +1 @@
-{"emptyGroups": false, "hideOfflineChums": true, "time12Format": true, "tabs": true, "soundon": true, "server": "irc.mindfang.org", "openDefaultGroup": true, "groups": [], "showSeconds": false, "showTimeStamps": false, "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "ircMonster", "twinArmageddons", "cannabisHero", "jetRocket", "adiosToreador", "turntechGodhead", "magmaExploiter", "hannaSongstress", "endlessVoid", "grayscaleVisionary", "corruptedInsanity", "stupidlyBrilliant", "artsyGyarados", "obliviousCrafter", "sporadicAgent", "subtleChaotician", "nareSolee", "apostateCourier", "nocturnalTherapist", "herpaDerp", "clockworkUtopia", "digitalSamurai", "astronomicalMaster", "slipshodBrisant", "genialDustbuster", "hyperdriveTyphoon", "magnificentMiser", "gentleRuffian", "riskRepeats", "globalsoftPrika", "globalsoftPirka", "devonianCritter", "lethargicSerpent", "bluntInstrument", "sunilaSeed", "ghostBinoculars", "cosmicSailor", "alGore", "evacipatedBox", "nickServ", "nakNak", "calSprite", "fairytalePorn", "moonbaseAlpha", "binaryRabbitlover"], "defaultprofile": "ghostDunk", "block": []}
\ No newline at end of file
+{"emptyGroups": false, "hideOfflineChums": true, "time12Format": true, "tabs": true, "soundon": true, "server": "irc.mindfang.org", "openDefaultGroup": true, "groups": [], "showSeconds": false, "showTimeStamps": false, "chums": ["unknownTraveler", "tentacleTherapist", "vaginalEngineer", "mechanicalSpectacle", "carcinoGeneticist", "schlagzeugGator", "gamblingGenocider", "gardenGnostic", "centaursTesticle", "arachnidsGrip", "grimAuxiliatrix", "remoteBloodbath", "nitroZealist", "greenZephyr", "arsenicCatnip", "cuttlefishCuller", "rageInducer", "gallowsCalibrator", "caligulasAquarium", "terminallyCapricious", "illuminatedWax", "aquaMarinist", "elegantDiversion", "moirailBunp", "uroborosUnbound", "androidTechnician", "midnightSparrow", "apocalypseArisen", "anguillaNuntia", "oilslickOrchid", "pretentiousFantasia", "aquaticMarinist", "lyricalKeraunoscopic", "counterRealist", "ectoBiologist", "percipientPedestrian", "asceticClinician", "doctectiveMiracles", "noSense", "ircMonster", "twinArmageddons", "cannabisHero", "jetRocket", "adiosToreador", "turntechGodhead", "magmaExploiter", "hannaSongstress", "endlessVoid", "grayscaleVisionary", "corruptedInsanity", "stupidlyBrilliant", "artsyGyarados", "obliviousCrafter", "sporadicAgent", "subtleChaotician", "nareSolee", "apostateCourier", "nocturnalTherapist", "herpaDerp", "clockworkUtopia", "digitalSamurai", "astronomicalMaster", "slipshodBrisant", "genialDustbuster", "hyperdriveTyphoon", "magnificentMiser", "gentleRuffian", "riskRepeats", "globalsoftPrika", "globalsoftPirka", "devonianCritter", "lethargicSerpent", "bluntInstrument", "sunilaSeed", "ghostBinoculars", "cosmicSailor", "alGore", "evacipatedBox", "nickServ", "nakNak", "calSprite", "fairytalePorn", "moonbaseAlpha", "binaryRabbitlover"], "defaultprofile": "testProfile", "block": []}
\ No newline at end of file