erc-speedbar.el 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. ;;; erc-speedbar.el --- Speedbar support for ERC
  2. ;; Copyright (C) 2001-2004, 2006-2012 Free Software Foundation, Inc.
  3. ;; Author: Mario Lang <mlang@delysid.org>
  4. ;; Contributor: Eric M. Ludlam <eric@siege-engine.com>
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This module provides integration of ERC into the Speedbar.
  18. ;;; TODO / ideas:
  19. ;; * Write intelligent update function:
  20. ;; update-channel, update-nick, remove-nick-from-channel, ...
  21. ;; * Use indicator-strings for op/voice
  22. ;; * Extract/convert face notes field from bbdb if available and show
  23. ;; it using sb-image.el
  24. ;;
  25. ;;; Code:
  26. (require 'erc)
  27. (require 'speedbar)
  28. (condition-case nil (require 'dframe) (error nil))
  29. (eval-when-compile (require 'cl))
  30. ;;; Customization:
  31. (defgroup erc-speedbar nil
  32. "Integration of ERC in the Speedbar"
  33. :group 'erc)
  34. (defcustom erc-speedbar-sort-users-type 'activity
  35. "How channel nicknames are sorted.
  36. 'activity - Sort users by channel activity
  37. 'alphabetical - Sort users alphabetically
  38. nil - Do not sort users"
  39. :group 'erc-speedbar
  40. :type '(choice (const :tag "Sort users by channel activity" activity)
  41. (const :tag "Sort users alphabetically" alphabetical)
  42. (const :tag "Do not sort users" nil)))
  43. (defvar erc-speedbar-key-map nil
  44. "Keymap used when in erc display mode.")
  45. (defun erc-install-speedbar-variables ()
  46. "Install those variables used by speedbar to enhance ERC."
  47. (if erc-speedbar-key-map
  48. nil
  49. (setq erc-speedbar-key-map (speedbar-make-specialized-keymap))
  50. ;; Basic tree features
  51. (define-key erc-speedbar-key-map "e" 'speedbar-edit-line)
  52. (define-key erc-speedbar-key-map "\C-m" 'speedbar-edit-line)
  53. (define-key erc-speedbar-key-map "+" 'speedbar-expand-line)
  54. (define-key erc-speedbar-key-map "=" 'speedbar-expand-line)
  55. (define-key erc-speedbar-key-map "-" 'speedbar-contract-line))
  56. (speedbar-add-expansion-list '("ERC" erc-speedbar-menu-items
  57. erc-speedbar-key-map
  58. erc-speedbar-server-buttons))
  59. (speedbar-add-mode-functions-list
  60. '("ERC" (speedbar-item-info . erc-speedbar-item-info))))
  61. (defvar erc-speedbar-menu-items
  62. '(["Goto buffer" speedbar-edit-line t]
  63. ["Expand Node" speedbar-expand-line
  64. (save-excursion (beginning-of-line)
  65. (looking-at "[0-9]+: *.\\+. "))]
  66. ["Contract Node" speedbar-contract-line
  67. (save-excursion (beginning-of-line)
  68. (looking-at "[0-9]+: *.-. "))])
  69. "Additional menu-items to add to speedbar frame.")
  70. ;; Make sure our special speedbar major mode is loaded
  71. (if (featurep 'speedbar)
  72. (erc-install-speedbar-variables)
  73. (add-hook 'speedbar-load-hook 'erc-install-speedbar-variables))
  74. ;;; ERC hierarchy display method
  75. ;;;###autoload
  76. (defun erc-speedbar-browser ()
  77. "Initialize speedbar to display an ERC browser.
  78. This will add a speedbar major display mode."
  79. (interactive)
  80. (require 'speedbar)
  81. ;; Make sure that speedbar is active
  82. (speedbar-frame-mode 1)
  83. ;; Now, throw us into Info mode on speedbar.
  84. (speedbar-change-initial-expansion-list "ERC")
  85. (speedbar-get-focus))
  86. (defun erc-speedbar-buttons (buffer)
  87. "Create buttons for speedbar in BUFFER."
  88. (erase-buffer)
  89. (let (serverp chanp queryp)
  90. (with-current-buffer buffer
  91. (setq serverp (erc-server-buffer-p))
  92. (setq chanp (erc-channel-p (erc-default-target)))
  93. (setq queryp (erc-query-buffer-p)))
  94. (cond (serverp
  95. (erc-speedbar-channel-buttons nil 0 buffer))
  96. (chanp
  97. (erc-speedbar-insert-target buffer 0)
  98. (forward-line -1)
  99. (erc-speedbar-expand-channel "+" buffer 0))
  100. (queryp
  101. (erc-speedbar-insert-target buffer 0))
  102. (t (ignore)))))
  103. (defun erc-speedbar-server-buttons (directory depth)
  104. "Insert the initial list of servers you are connected to."
  105. (let ((servers (erc-buffer-list
  106. (lambda ()
  107. (eq (current-buffer)
  108. (process-buffer erc-server-process))))))
  109. (when servers
  110. (speedbar-with-writable
  111. (dolist (server servers)
  112. (speedbar-make-tag-line
  113. 'bracket ?+ 'erc-speedbar-expand-server server
  114. (buffer-name server) 'erc-speedbar-goto-buffer server nil
  115. depth))
  116. t))))
  117. (defun erc-speedbar-expand-server (text server indent)
  118. (cond ((string-match "+" text)
  119. (speedbar-change-expand-button-char ?-)
  120. (if (speedbar-with-writable
  121. (save-excursion
  122. (end-of-line) (forward-char 1)
  123. (erc-speedbar-channel-buttons nil (1+ indent) server)))
  124. (speedbar-change-expand-button-char ?-)
  125. (speedbar-change-expand-button-char ??)))
  126. ((string-match "-" text) ;we have to contract this node
  127. (speedbar-change-expand-button-char ?+)
  128. (speedbar-delete-subblock indent))
  129. (t (error "Ooops... not sure what to do")))
  130. (speedbar-center-buffer-smartly))
  131. (defun erc-speedbar-channel-buttons (directory depth server-buffer)
  132. (when (get-buffer server-buffer)
  133. (let* ((proc (with-current-buffer server-buffer erc-server-process))
  134. (targets (erc-buffer-list
  135. (lambda ()
  136. (not (eq (process-buffer erc-server-process)
  137. (current-buffer))))
  138. proc)))
  139. (when targets
  140. (speedbar-with-writable
  141. (dolist (target targets)
  142. (erc-speedbar-insert-target target depth))
  143. t)))))
  144. (defun erc-speedbar-insert-target (buffer depth)
  145. (if (with-current-buffer buffer
  146. (erc-channel-p (erc-default-target)))
  147. (speedbar-make-tag-line
  148. 'bracket ?+ 'erc-speedbar-expand-channel buffer
  149. (buffer-name buffer) 'erc-speedbar-goto-buffer buffer nil
  150. depth)
  151. ;; Query target
  152. (speedbar-make-tag-line
  153. nil nil nil nil
  154. (buffer-name buffer) 'erc-speedbar-goto-buffer buffer nil
  155. depth)))
  156. (defun erc-speedbar-expand-channel (text channel indent)
  157. "For the line matching TEXT, in CHANNEL, expand or contract a line.
  158. INDENT is the current indentation level."
  159. (cond
  160. ((string-match "+" text)
  161. (speedbar-change-expand-button-char ?-)
  162. (speedbar-with-writable
  163. (save-excursion
  164. (end-of-line) (forward-char 1)
  165. (let ((modes (with-current-buffer channel
  166. (concat (apply 'concat
  167. erc-channel-modes)
  168. (cond
  169. ((and erc-channel-user-limit
  170. erc-channel-key)
  171. (if erc-show-channel-key-p
  172. (format "lk %.0f %s"
  173. erc-channel-user-limit
  174. erc-channel-key)
  175. (format "kl %.0f" erc-channel-user-limit)))
  176. (erc-channel-user-limit
  177. ;; Emacs has no bignums
  178. (format "l %.0f" erc-channel-user-limit))
  179. (erc-channel-key
  180. (if erc-show-channel-key-p
  181. (format "k %s" erc-channel-key)
  182. "k"))
  183. (t "")))))
  184. (topic (erc-controls-interpret
  185. (with-current-buffer channel erc-channel-topic))))
  186. (speedbar-make-tag-line
  187. 'angle ?i nil nil
  188. (concat "Modes: +" modes) nil nil nil
  189. (1+ indent))
  190. (unless (string= topic "")
  191. (speedbar-make-tag-line
  192. 'angle ?i nil nil
  193. (concat "Topic: " topic) nil nil nil
  194. (1+ indent)))
  195. (let ((names (cond ((eq erc-speedbar-sort-users-type 'alphabetical)
  196. (erc-sort-channel-users-alphabetically
  197. (with-current-buffer channel
  198. (erc-get-channel-user-list))))
  199. ((eq erc-speedbar-sort-users-type 'activity)
  200. (erc-sort-channel-users-by-activity
  201. (with-current-buffer channel
  202. (erc-get-channel-user-list))))
  203. (t (with-current-buffer channel
  204. (erc-get-channel-user-list))))))
  205. (when names
  206. (speedbar-with-writable
  207. (dolist (entry names)
  208. (erc-speedbar-insert-user entry ?+ (1+ indent))))))))))
  209. ((string-match "-" text)
  210. (speedbar-change-expand-button-char ?+)
  211. (speedbar-delete-subblock indent))
  212. (t (error "Ooops... not sure what to do")))
  213. (speedbar-center-buffer-smartly))
  214. (defun erc-speedbar-insert-user (entry exp-char indent)
  215. "Insert one user based on the channel member list ENTRY.
  216. EXP-CHAR is the expansion character to use.
  217. INDENT is the current indentation level."
  218. (let* ((user (car entry))
  219. (cuser (cdr entry))
  220. (nick (erc-server-user-nickname user))
  221. (host (erc-server-user-host user))
  222. (info (erc-server-user-info user))
  223. (login (erc-server-user-login user))
  224. (name (erc-server-user-full-name user))
  225. (voice (and cuser (erc-channel-user-voice cuser)))
  226. (op (and cuser (erc-channel-user-op cuser)))
  227. (nick-str (concat (if op "@" "") (if voice "+" "") nick))
  228. (finger (concat login (when (or login host) "@") host))
  229. (sbtoken (list finger name info)))
  230. (if (or login host name info) ; we want to be expandable
  231. (speedbar-make-tag-line
  232. 'bracket ?+ 'erc-speedbar-expand-user sbtoken
  233. nick-str nil sbtoken nil
  234. indent)
  235. (when (equal exp-char ?-)
  236. (forward-line -1)
  237. (erc-speedbar-expand-user "+" (list finger name info) indent))
  238. (speedbar-make-tag-line
  239. 'statictag ?? nil nil
  240. nick-str nil nil nil
  241. indent))))
  242. (defun erc-speedbar-update-channel (buffer)
  243. "Update the speedbar information about a ERC buffer. The update
  244. is only done when the channel is actually expanded already."
  245. ;; This is only a rude hack and doesn't care about multiserver usage
  246. ;; yet, consider this a brain storming, better ideas?
  247. (with-current-buffer speedbar-buffer
  248. (save-excursion
  249. (goto-char (point-min))
  250. (when (re-search-forward (concat "^1: *.+. *"
  251. (regexp-quote (buffer-name buffer)))
  252. nil t)
  253. (beginning-of-line)
  254. (speedbar-delete-subblock 1)
  255. (erc-speedbar-expand-channel "+" buffer 1)))))
  256. (defun erc-speedbar-expand-user (text token indent)
  257. (cond ((string-match "+" text)
  258. (speedbar-change-expand-button-char ?-)
  259. (speedbar-with-writable
  260. (save-excursion
  261. (end-of-line) (forward-char 1)
  262. (let ((finger (nth 0 token))
  263. (name (nth 1 token))
  264. (info (nth 2 token)))
  265. (when finger
  266. (speedbar-make-tag-line
  267. nil nil nil nil
  268. finger nil nil nil
  269. (1+ indent)))
  270. (when name
  271. (speedbar-make-tag-line
  272. nil nil nil nil
  273. name nil nil nil
  274. (1+ indent)))
  275. (when info
  276. (speedbar-make-tag-line
  277. nil nil nil nil
  278. info nil nil nil
  279. (1+ indent)))))))
  280. ((string-match "-" text)
  281. (speedbar-change-expand-button-char ?+)
  282. (speedbar-delete-subblock indent))
  283. (t (error "Ooops... not sure what to do")))
  284. (speedbar-center-buffer-smartly))
  285. (defun erc-speedbar-goto-buffer (text buffer indent)
  286. "When user clicks on TEXT, goto an ERC buffer.
  287. The INDENT level is ignored."
  288. (if (featurep 'dframe)
  289. (progn
  290. (dframe-select-attached-frame speedbar-frame)
  291. (let ((bwin (get-buffer-window buffer 0)))
  292. (if bwin
  293. (progn
  294. (select-window bwin)
  295. (raise-frame (window-frame bwin)))
  296. (if dframe-power-click
  297. (let ((pop-up-frames t))
  298. (select-window (display-buffer buffer)))
  299. (dframe-select-attached-frame speedbar-frame)
  300. (switch-to-buffer buffer)))))
  301. (let ((bwin (get-buffer-window buffer 0)))
  302. (if bwin
  303. (progn
  304. (select-window bwin)
  305. (raise-frame (window-frame bwin)))
  306. (if speedbar-power-click
  307. (let ((pop-up-frames t)) (select-window (display-buffer buffer)))
  308. (dframe-select-attached-frame speedbar-frame)
  309. (switch-to-buffer buffer))))))
  310. (defun erc-speedbar-line-text ()
  311. "Return the text for the item on the current line."
  312. (beginning-of-line)
  313. (when (re-search-forward "[]>] " nil t)
  314. (buffer-substring-no-properties (point) (point-at-eol))))
  315. (defun erc-speedbar-item-info ()
  316. "Display information about the current buffer on the current line."
  317. (let ((data (speedbar-line-token))
  318. (txt (erc-speedbar-line-text)))
  319. (cond ((and data (listp data))
  320. (message "%s: %s" txt (car data)))
  321. ((bufferp data)
  322. (message "Channel: %s" txt))
  323. (t
  324. (message "%s" txt)))))
  325. (provide 'erc-speedbar)
  326. ;;; erc-speedbar.el ends here
  327. ;;
  328. ;; Local Variables:
  329. ;; indent-tabs-mode: t
  330. ;; tab-width: 8
  331. ;; End: