public
Description: Campfire major mode for emacs
Homepage:
Clone URL: git://github.com/rubyist/campfire-mode.git
campfire-mode / campfire-mode.rb
100644 215 lines (170 sloc) 6.609 kb
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
## campfire-mode.rb --- Major mode for Campfire
 
# Copyright (C) 2007 Scott Barron.
 
# Author: Scott Barron <scott@theedgecase.com>
# Created: Nov 20, 2007
# Version: $Rev: 121 $
# Keywords: campfire web
# URL: http://opensource.edgerepo.com/text/emacs/campfire-mode/README
 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
#; Commentary:
 
# campfire-mode.el is a major mode for Campfire.
# You can login to a campfire room and read and post messages in Emacs.
 
require 'singleton'
require 'rubygems'
gem 'tinder'
require 'tinder'
 
defvar :campfire_mode_map, make_sparse_keymap
 
defvar :campfire_timer, nil
 
defvar :campfire_timer_interval, 30
 
defvar :campfire_username, nil
 
defvar :campfire_password, nil
 
defvar :campfire_domain, nil
 
defvar :campfire_room, nil
 
defvar :campfire_username_face, :campfire_username_face
 
defvar :campfire_buffer, '*campfire*'
defun(:campfire_buffer) do
  campfire_get_or_generate_buffer campfire_buffer
end
 
defun(:campfire_get_or_generate_buffer) do |buffer|
  bufferp(buffer) ? buffer : generate_new_buffer(buffer)
end
 
if elvar.campfire_mode_map
  define_key elvar.campfire_mode_map, "\C-c\C-s", :campfire_speak
end
 
# Monkey patching tinder
class Tinder::Room
  attr_reader :user_name
  
  def join(force=false)
    @room = returning(get("room/#{id}")) do |room|
      raise Error, "Could not join room" unless verify_response(room, :success)
      @membership_key = room.body.scan(/\"membershipKey\": \"([a-z0-9]+)\"/).to_s
      @user_id = room.body.scan(/\"userID\": (\d+)/).to_s
      @user_name = room.body.scan(/\s*window\.chat(.*)/).to_s.scan(/<td class=\\"person\\"><span>(.+)<\/span>/).to_s
      @last_cache_id = room.body.scan(/\"lastCacheID\": (\d+)/).to_s
      @timestamp = room.body.scan(/\"timestamp\": (\d+)/).to_s
    end if @room.nil? || force
    true
  end
end
# End monkey patching tinder
 
 
class CampfireMode
  include Singleton
  include ElMixin
  
  def start
    @campfire = Tinder::Campfire.new elvar.campfire_domain
    @campfire.login elvar.campfire_username, elvar.campfire_password
    unless @room = @campfire.find_room_by_name(elvar.campfire_room)
      message "Could not find campfire room #{elvar.campfire_room}"
      return
    end
    @room.join
 
    transcript = @room.transcript(@room.available_transcripts.first)
    transcript.each do |msg|
      with(:with_current_buffer, elvar.campfire_buffer) do
        render_message(msg[:person], msg[:message])
      end
    end
    
    message "starting campfire"
    elvar.campfire_timer = run_at_time '0 sec', elvar.campfire_timer_interval, :campfire_update
  end
 
  def stop
    @room.leave
    @campfire.logout
    kill_buffer elvar.campfire_buffer # For some reason, don't use the function here
  end
 
  def speak(msg)
    @room.speak msg
    render_message @room.user_name, msg
  end
 
  def paste(msg)
    @room.paste msg
    render_message @room.user_name, msg
  end
 
  def update
    messages = @room.listen
    messages.each do |msg|
      render_message(msg[:person], msg[:message])
    end
  end
 
  def render_message(person, msg)
    return if person.blank?
 
    with(:with_current_buffer, elvar.campfire_buffer) do
      elvar.buffer_read_only = nil
      end_of_buffer
 
      # Look for inline images, uploads, and pastesxb
      if msg =~ /onload="loadInlineImage\(this\)"/
        msg =~ /img src="(.+)" alt/
        msg_text = "[Inline Image] #{$1}"
      elsif msg =~ /a href="(\/room\/\d+\/uploads\/\d+\/[^\s]+)"/
        msg_text = "[Upload] http://#{elvar.campfire_domain}.campfirenow.com#{$1}"
      elsif msg =~ /(\/room\/\d+\/paste\/\d+)/
        msg_text = "[Paste] http://#{elvar.campfire_domain}.campfirenow.com#{$1}\n"
        msg =~ /<pre><code>(.*)<\/code><\/pre>/m
        msg_text << $1
      else
        msg_text = msg
      end
      
      current_max = point_max
      insert "#{person}\n #{msg_text}\n\n"
 
      # Since I'm unable to add_text_properties to the string in el4r, calculate it for the
      # whole buffer using the point prior to insertion
      add_text_properties current_max, current_max + person.size, [:mouse_face, :highlight, :face, :campfire_username_face], get_buffer(elvar.campfire_buffer)
      
      elvar.buffer_read_only = true
      end_of_buffer
    end
  end
end
 
defun :campfire_mode_init_variables do
  # I can't figure out how to defface or set_face_attribute from el4r
  font_lock_mode -1
  el4r_lisp_eval "(defface campfire-username-face `((t nil)) "" :group 'face)"
  copy_face :font_lock_string_face, :campfire_username_face
  el4r_lisp_eval "(set-face-attribute 'campfire-username-face nil :underline t)"
end
 
defun(:campfire_update) do
  CampfireMode.instance.update
end
 
defun(:campfire_speak, :interactive => "sMessage: ") do |msg|
  CampfireMode.instance.speak(msg)
end
 
defun(:campfire_paste_region, :interactive => "r") do |first, last|
  CampfireMode.instance.paste(buffer_substring(first, last))
end
 
defun(:campfire_paste_buffer, :interactive => true) do
  CampfireMode.instance.paste(buffer_string)
end
 
defun(:campfire_stop, :interactive => true) do
  CampfireMode.instance.stop
  cancel_timer elvar.campfire_timer
end
 
defun(:campfire_mode, :docstring => "Major mode for Campfire", :interactive => true) do
  switch_to_buffer elvar.campfire_buffer
  kill_all_local_variables
  campfire_mode_init_variables
  use_local_map elvar.campfire_mode_map
  elvar.major_mode = :campfire_mode
  elvar.mode_name = "Campfire mode"
  campfire_mode_init_variables
  font_lock_mode -1
  begin
    CampfireMode.instance.start
  rescue Exception => e
    puts e.inspect
  end
end
 
provide(:campfire_mode)