-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
weechat-read-marker.el
143 lines (113 loc) · 5.07 KB
/
weechat-read-marker.el
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
;;; weechat-read-marker.el --- read marker for WeeChat -*- lexical-binding: t -*-
;; Copyright (C) 2015 Hans-Peter Deifel
;; Author: Hans-Peter Deifel <hpd@hpdeifel.de>
;; Created: 22 Jun 2015
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2, or (at
;; your option) any later version.
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;;; Draw a thin red line between the read and unread lines in a buffer.
;;; See `M-x customize-group weechat-read-marker' for configuration options.
;;; If anything goes wrong, the read marker can be manually reset with
;;; `weechat-read-marker-reset'.
;;; Code:
(require 'weechat)
(defgroup weechat-read-marker nil
"Read marker for WeeChat"
:prefix "weechat-read-marker"
:group 'weechat)
(defcustom weechat-read-marker-char ?─
"Character used to render the read marker."
:type 'character
:group 'weechat-read-marker)
(defface weechat-read-marker
'((t :foreground "brown"))
"Face used to colorize the read marker."
:group 'weechat-read-marker)
(defcustom weechat-read-marker-always-show nil
"Always show read marker, even if it is after last buffer line.
A value of t means that the read marker is displayed directly
over the prompt, if there are no unread lines. With nil, the
marker is simply not displayed in this case."
:type 'boolean
:group 'weechat-read-marker)
(defvar-local weechat-read-marker-overlay nil
"The overlay used to draw the read marker.
Will be nil initially and if the buffer has no unread lines when
`weechat-read-marker-always-show` is not set.")
(defvar-local weechat-read-marker-stale t
"Whether the read marker position is outdated.
This will be set if the buffer is visited, to indicate that the
unread lines are now read.")
(defun weechat-read-marker--set-overlay ()
"Update the `after-string' property on an already existing overlay."
(let* ((width (- (window-width) 1))
(line (make-string width weechat-read-marker-char)))
(overlay-put weechat-read-marker-overlay 'after-string
(concat "\n" (propertize line 'face 'weechat-read-marker)))))
(defun weechat-read-marker--move-overlay ()
"Update the read marker in the current buffer."
(if weechat-read-marker-overlay
(move-overlay weechat-read-marker-overlay (point-at-bol) (point-at-eol))
(setq weechat-read-marker-overlay
(make-overlay (point-at-bol) (point-at-eol) nil t nil))
;; Delete overlay if text is deleted. This is needed to get rid of the
;; overlay, when the buffer is reset.
(overlay-put weechat-read-marker-overlay 'evaporate t))
(weechat-read-marker--set-overlay))
(defun weechat-read-marker-handle-visited ()
"Reset read marker after a buffer is being visited."
(if weechat-read-marker-stale
;; we haven't had any new lines. Reset overlay
(when weechat-read-marker-overlay
(if weechat-read-marker-always-show
(save-excursion
(goto-char (point-max))
(forward-line -1)
(weechat-read-marker--move-overlay))
(delete-overlay weechat-read-marker-overlay)
(setq weechat-read-marker-overlay nil)))
;; otherwise, set the read marker to be stale
(setq weechat-read-marker-stale t)
;; and also recompute the overlay string, since the window-width could have
;; changed
(when weechat-read-marker-overlay
(weechat-read-marker--set-overlay))))
(defun weechat-read-marker-handle-background ()
"Move read-marker in case it is stale."
(when weechat-read-marker-stale
(save-excursion
(goto-char (point-max))
(unless (< (line-number-at-pos) 3)
(forward-line -2)
(weechat-read-marker--move-overlay)
(setq weechat-read-marker-stale nil)))))
(defun weechat-read-marker-reset ()
"Manually reset the read marker in the current buffer."
(interactive "")
(when weechat-read-marker-overlay
;; Always delete (and possibly) recreate overlay in case anything went wrong
;; and the users used this command to reset things.
(delete-overlay weechat-read-marker-overlay)
(if weechat-read-marker-always-show
(save-excursion
(goto-char (point-max))
(forward-line -1)
(weechat-read-marker--set-overlay))
(setq weechat-read-marker-overlay nil)))
(setq weechat-read-marker-stale t))
(add-hook 'weechat-buffer-background-message-hook
'weechat-read-marker-handle-background)
(add-hook 'weechat-buffer-visited-hook
'weechat-read-marker-handle-visited)
(provide 'weechat-read-marker)
;;; weechat-read-marker.el ends here