diff options
| author | Josh Feinstein | 2012-08-20 09:08:51 -0700 |
|---|---|---|
| committer | Josh Feinstein | 2012-08-20 09:08:51 -0700 |
| commit | 487a247f1d48faac2aa789baddd5ee5d7fa28d4a (patch) | |
| tree | 19d7148692b9c9b5eaac8414903b8c1dc1206966 | |
| parent | a32fbbcf262a71891032ef84f596bf5525f9124a (diff) | |
| download | emacs-487a247f1d48faac2aa789baddd5ee5d7fa28d4a.tar.gz emacs-487a247f1d48faac2aa789baddd5ee5d7fa28d4a.zip | |
Hide specified message types sent by lurkers
* erc.el (erc-display-message): Abstract message hiding decision
to new function erc-hide-current-message-p.
(erc-lurker): New customization group.
(erc-lurker-state, erc-lurker-trim-nicks, erc-lurker-ignore-chars)
(erc-lurker-hide-list, erc-lurker-cleanup-interval)
(erc-lurker-threshold-time): New variables.
(erc-lurker-maybe-trim, erc-lurker-initialize, erc-lurker-cleanup)
(erc-hide-current-message-p, erc-canonicalize-server-name)
(erc-lurker-update-status, erc-lurker-p): New functions. Together
they maintain state about which users have spoken in the last
erc-lurker-threshold-time, with all other users being considered
lurkers whose messages of types in erc-lurker-hide-list will not
be displayed by erc-display-message.
| -rw-r--r-- | lisp/erc/ChangeLog | 16 | ||||
| -rw-r--r-- | lisp/erc/erc.el | 174 |
2 files changed, 189 insertions, 1 deletions
diff --git a/lisp/erc/ChangeLog b/lisp/erc/ChangeLog index b87cfd41f61..dd62cae7de1 100644 --- a/lisp/erc/ChangeLog +++ b/lisp/erc/ChangeLog | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | 2012-08-20 Josh Feinstein <jlf@foxtail.org> | ||
| 2 | |||
| 3 | * erc.el (erc-display-message): Abstract message hiding decision | ||
| 4 | to new function erc-hide-current-message-p. | ||
| 5 | (erc-lurker): New customization group. | ||
| 6 | (erc-lurker-state, erc-lurker-trim-nicks, erc-lurker-ignore-chars) | ||
| 7 | (erc-lurker-hide-list, erc-lurker-cleanup-interval) | ||
| 8 | (erc-lurker-threshold-time): New variables. | ||
| 9 | (erc-lurker-maybe-trim, erc-lurker-initialize, erc-lurker-cleanup) | ||
| 10 | (erc-hide-current-message-p, erc-canonicalize-server-name) | ||
| 11 | (erc-lurker-update-status, erc-lurker-p): New functions. Together | ||
| 12 | they maintain state about which users have spoken in the last | ||
| 13 | erc-lurker-threshold-time, with all other users being considered | ||
| 14 | lurkers whose messages of types in erc-lurker-hide-list will not | ||
| 15 | be displayed by erc-display-message. | ||
| 16 | |||
| 1 | 2012-08-06 Julien Danjou <julien@danjou.info> | 17 | 2012-08-06 Julien Danjou <julien@danjou.info> |
| 2 | 18 | ||
| 3 | * erc-match.el (erc-match-exclude-server-buffer) | 19 | * erc-match.el (erc-match-exclude-server-buffer) |
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 0fc308621b1..feef75940f3 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el | |||
| @@ -100,6 +100,10 @@ | |||
| 100 | "Ignoring certain messages" | 100 | "Ignoring certain messages" |
| 101 | :group 'erc) | 101 | :group 'erc) |
| 102 | 102 | ||
| 103 | (defgroup erc-lurker nil | ||
| 104 | "Hide specified message types sent by lurkers" | ||
| 105 | :group 'erc-ignore) | ||
| 106 | |||
| 103 | (defgroup erc-query nil | 107 | (defgroup erc-query nil |
| 104 | "Using separate buffers for private discussions" | 108 | "Using separate buffers for private discussions" |
| 105 | :group 'erc) | 109 | :group 'erc) |
| @@ -2455,6 +2459,174 @@ See also `erc-make-notice'." | |||
| 2455 | string) | 2459 | string) |
| 2456 | string))) | 2460 | string))) |
| 2457 | 2461 | ||
| 2462 | (defvar erc-lurker-state nil | ||
| 2463 | "Track the time of the last PRIVMSG for each (server,nick) pair. | ||
| 2464 | |||
| 2465 | This is implemented as a hash of hashes, where the outer key is | ||
| 2466 | the canonicalized server name (as returned by | ||
| 2467 | `erc-canonicalize-server-name') and the outer value is a hash | ||
| 2468 | table mapping nicks (as returned by `erc-lurker-maybe-trim') to | ||
| 2469 | the times of their most recently received PRIVMSG on any channel | ||
| 2470 | on the given server.") | ||
| 2471 | |||
| 2472 | (defcustom erc-lurker-trim-nicks t | ||
| 2473 | "If t, trim trailing `erc-lurker-ignore-chars' from nicks. | ||
| 2474 | |||
| 2475 | This causes e.g. nick and nick` to be considered as the same | ||
| 2476 | individual for activity tracking and lurkiness detection | ||
| 2477 | purposes." | ||
| 2478 | :group 'erc-lurker | ||
| 2479 | :type 'boolean) | ||
| 2480 | |||
| 2481 | (defun erc-lurker-maybe-trim (nick) | ||
| 2482 | "Maybe trim trailing `erc-lurker-ignore-chars' from NICK. | ||
| 2483 | |||
| 2484 | Returns NICK unmodified unless `erc-lurker-trim-nicks' is | ||
| 2485 | non-nil." | ||
| 2486 | (if erc-lurker-trim-nicks | ||
| 2487 | (replace-regexp-in-string | ||
| 2488 | (format "[%s]" | ||
| 2489 | (mapconcat (lambda (char) | ||
| 2490 | (regexp-quote (char-to-string char))) | ||
| 2491 | erc-lurker-ignore-chars "")) | ||
| 2492 | "" nick) | ||
| 2493 | nick)) | ||
| 2494 | |||
| 2495 | (defcustom erc-lurker-ignore-chars "`_" | ||
| 2496 | "Characters at the end of a nick to strip for activity tracking purposes. | ||
| 2497 | |||
| 2498 | See also `erc-lurker-trim-nicks'." | ||
| 2499 | :group 'erc-lurker | ||
| 2500 | :type 'string) | ||
| 2501 | |||
| 2502 | (defcustom erc-lurker-hide-list nil | ||
| 2503 | "List of IRC type messages to hide when sent by lurkers. | ||
| 2504 | |||
| 2505 | A typical value would be '(\"JOIN\" \"PART\" \"QUIT\"). | ||
| 2506 | See also `erc-lurker-p' and `erc-hide-list'." | ||
| 2507 | :group 'erc-lurker | ||
| 2508 | :type 'erc-message-type) | ||
| 2509 | |||
| 2510 | (defcustom erc-lurker-threshold-time (* 60 60 24) ; 24h by default | ||
| 2511 | "Nicks from which no PRIVMSGs have been received within this | ||
| 2512 | interval (in units of seconds) are considered lurkers by | ||
| 2513 | `erc-lurker-p' and as a result their messages of types in | ||
| 2514 | `erc-lurker-hide-list' will be hidden." | ||
| 2515 | :group 'erc-lurker | ||
| 2516 | :type 'integer) | ||
| 2517 | |||
| 2518 | (defun erc-lurker-initialize () | ||
| 2519 | "Initialize ERC lurker tracking functionality. | ||
| 2520 | |||
| 2521 | This function adds `erc-lurker-update-status' to | ||
| 2522 | `erc-insert-pre-hook' in order to record the time of each nick's | ||
| 2523 | most recent PRIVMSG as well as initializing the state variable | ||
| 2524 | storing this information." | ||
| 2525 | (setq erc-lurker-state (make-hash-table :test 'equal)) | ||
| 2526 | (add-hook 'erc-insert-pre-hook 'erc-lurker-update-status)) | ||
| 2527 | |||
| 2528 | (defun erc-lurker-cleanup () | ||
| 2529 | "Remove all last PRIVMSG state older than `erc-lurker-threshold-time'. | ||
| 2530 | |||
| 2531 | This should be called regularly to avoid excessive resource | ||
| 2532 | consumption for long-lived IRC or Emacs sessions." | ||
| 2533 | (maphash | ||
| 2534 | (lambda (server hash) | ||
| 2535 | (maphash | ||
| 2536 | (lambda (nick last-PRIVMSG-time) | ||
| 2537 | (when | ||
| 2538 | (> (time-to-seconds (time-subtract | ||
| 2539 | (current-time) | ||
| 2540 | last-PRIVMSG-time)) | ||
| 2541 | erc-lurker-threshold-time) | ||
| 2542 | (remhash nick hash))) | ||
| 2543 | hash) | ||
| 2544 | (if (zerop (hash-table-count hash)) | ||
| 2545 | (remhash server erc-lurker-state))) | ||
| 2546 | erc-lurker-state)) | ||
| 2547 | |||
| 2548 | (defvar erc-lurker-cleanup-count 0 | ||
| 2549 | "Internal counter variable for use with `erc-lurker-cleanup-interval'.") | ||
| 2550 | |||
| 2551 | (defvar erc-lurker-cleanup-interval 100 | ||
| 2552 | "Specifies frequency of cleaning up stale erc-lurker state. | ||
| 2553 | |||
| 2554 | `erc-lurker-update-status' calls `erc-lurker-cleanup' once for | ||
| 2555 | every `erc-lurker-cleanup-interval' updates to | ||
| 2556 | `erc-lurker-state'. This is designed to limit the memory | ||
| 2557 | consumption of lurker state during long Emacs sessions and/or ERC | ||
| 2558 | sessions with large numbers of incoming PRIVMSGs.") | ||
| 2559 | |||
| 2560 | (defun erc-lurker-update-status (message) | ||
| 2561 | "Update `erc-lurker-state' if necessary. | ||
| 2562 | |||
| 2563 | This function is called from `erc-insert-pre-hook'. If the | ||
| 2564 | current message is a PRIVMSG, update `erc-lurker-state' to | ||
| 2565 | reflect the fact that its sender has issued a PRIVMSG at the | ||
| 2566 | current time. Otherwise, take no action. | ||
| 2567 | |||
| 2568 | This function depends on the fact that `erc-display-message' | ||
| 2569 | dynamically binds `parsed', which is used to check if the current | ||
| 2570 | message is a PRIVMSG and to determine its sender. See also | ||
| 2571 | `erc-lurker-trim-nicks' and `erc-lurker-ignore-chars'. | ||
| 2572 | |||
| 2573 | In order to limit memory consumption, this function also calls | ||
| 2574 | `erc-lurker-cleanup' once every `erc-lurker-cleanup-interval' | ||
| 2575 | updates of `erc-lurker-state'." | ||
| 2576 | (when (and (boundp 'parsed) (erc-response-p parsed)) | ||
| 2577 | (let* ((command (erc-response.command parsed)) | ||
| 2578 | (sender | ||
| 2579 | (erc-lurker-maybe-trim | ||
| 2580 | (car (erc-parse-user (erc-response.sender parsed))))) | ||
| 2581 | (server | ||
| 2582 | (erc-canonicalize-server-name erc-server-announced-name))) | ||
| 2583 | (when (equal command "PRIVMSG") | ||
| 2584 | (when (>= (incf erc-lurker-cleanup-count) erc-lurker-cleanup-interval) | ||
| 2585 | (setq erc-lurker-cleanup-count 0) | ||
| 2586 | (erc-lurker-cleanup)) | ||
| 2587 | (unless (gethash server erc-lurker-state) | ||
| 2588 | (puthash server (make-hash-table :test 'equal) erc-lurker-state)) | ||
| 2589 | (puthash sender (current-time) | ||
| 2590 | (gethash server erc-lurker-state)))))) | ||
| 2591 | |||
| 2592 | (defun erc-lurker-p (nick) | ||
| 2593 | "Predicate indicating NICK's lurking status on the current server. | ||
| 2594 | |||
| 2595 | Lurking is the condition where NICK has issued no PRIVMSG on this | ||
| 2596 | server within `erc-lurker-threshold-time'. See also | ||
| 2597 | `erc-lurker-trim-nicks' and `erc-lurker-ignore-chars'." | ||
| 2598 | (unless erc-lurker-state (erc-lurker-initialize)) | ||
| 2599 | (let* ((server | ||
| 2600 | (erc-canonicalize-server-name erc-server-announced-name)) | ||
| 2601 | (last-PRIVMSG-time | ||
| 2602 | (gethash (erc-lurker-maybe-trim nick) | ||
| 2603 | (gethash server erc-lurker-state (make-hash-table))))) | ||
| 2604 | (or (null last-PRIVMSG-time) | ||
| 2605 | (> (time-to-seconds | ||
| 2606 | (time-subtract (current-time) last-PRIVMSG-time)) | ||
| 2607 | erc-lurker-threshold-time)))) | ||
| 2608 | |||
| 2609 | (defun erc-canonicalize-server-name (server) | ||
| 2610 | "Returns the canonical network name for SERVER if any, | ||
| 2611 | otherwise `erc-server-announced-name'. SERVER is matched against | ||
| 2612 | `erc-common-server-suffixes'." | ||
| 2613 | (when server | ||
| 2614 | (or (cdar (erc-remove-if-not | ||
| 2615 | (lambda (net) (string-match (car net) server)) | ||
| 2616 | erc-common-server-suffixes)) | ||
| 2617 | erc-server-announced-name))) | ||
| 2618 | |||
| 2619 | (defun erc-hide-current-message-p (parsed) | ||
| 2620 | "Predicate indicating whether the parsed ERC response PARSED should be hidden. | ||
| 2621 | |||
| 2622 | Messages are always hidden if the message type of PARSED appears in | ||
| 2623 | `erc-hide-list'. In addition, messages whose type is a member of | ||
| 2624 | `erc-lurker-hide-list' are hidden if `erc-lurker-p' returns true." | ||
| 2625 | (let* ((command (erc-response.command parsed)) | ||
| 2626 | (sender (car (erc-parse-user (erc-response.sender parsed))))) | ||
| 2627 | (or (member command erc-hide-list) | ||
| 2628 | (and (member command erc-lurker-hide-list) (erc-lurker-p sender))))) | ||
| 2629 | |||
| 2458 | (defun erc-display-message (parsed type buffer msg &rest args) | 2630 | (defun erc-display-message (parsed type buffer msg &rest args) |
| 2459 | "Display MSG in BUFFER. | 2631 | "Display MSG in BUFFER. |
| 2460 | 2632 | ||
| @@ -2479,7 +2651,7 @@ See also `erc-format-message' and `erc-display-line'." | |||
| 2479 | 2651 | ||
| 2480 | (if (not (erc-response-p parsed)) | 2652 | (if (not (erc-response-p parsed)) |
| 2481 | (erc-display-line string buffer) | 2653 | (erc-display-line string buffer) |
| 2482 | (unless (member (erc-response.command parsed) erc-hide-list) | 2654 | (unless (erc-hide-current-message-p parsed) |
| 2483 | (erc-put-text-property 0 (length string) 'erc-parsed parsed string) | 2655 | (erc-put-text-property 0 (length string) 'erc-parsed parsed string) |
| 2484 | (erc-put-text-property 0 (length string) 'rear-sticky t string) | 2656 | (erc-put-text-property 0 (length string) 'rear-sticky t string) |
| 2485 | (erc-display-line string buffer))))) | 2657 | (erc-display-line string buffer))))) |