]> git.rkrishnan.org Git - .emacs.d.git/blob - emacs/nxhtml/related/mozadd.el
remove toolbar and menubar
[.emacs.d.git] / emacs / nxhtml / related / mozadd.el
1 ;;; mozadd.el --- Additional functionality for MozRepl
2 ;;
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Created: 2009-07-22 Wed
5 (defconst mozadd:version "0.2") ;; Version:
6 ;; Last-Updated: 2009-08-04 Tue
7 ;; URL:
8 ;; Keywords:
9 ;; Compatibility:
10 ;;
11 ;; Features that might be required by this library:
12 ;;
13   ;; `cc-cmds', `cc-defs', `cc-engine', `cc-vars', `comint', `json',
14   ;; `moz', `regexp-opt', `ring'.
15 ;;
16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17 ;;
18 ;;; Commentary:
19 ;;
20 ;; Live tracking of editing changes, see
21 ;;   `mozadd-mirror-mode'
22 ;;   `mozadd-refresh-edited-on-save-mode'
23 ;;
24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;;
26 ;;; Change log:
27 ;;
28 ;;
29 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
30 ;;
31 ;; This program is free software; you can redistribute it and/or
32 ;; modify it under the terms of the GNU General Public License as
33 ;; published by the Free Software Foundation; either version 3, or
34 ;; (at your option) any later version.
35 ;;
36 ;; This program is distributed in the hope that it will be useful,
37 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
38 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39 ;; General Public License for more details.
40 ;;
41 ;; You should have received a copy of the GNU General Public License
42 ;; along with this program; see the file COPYING.  If not, write to
43 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
44 ;; Floor, Boston, MA 02110-1301, USA.
45 ;;
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 ;;
48 ;;; Code:
49
50 (require 'moz)
51 (require 'json)
52
53 (defun mozadd-warning (format-string &rest args)
54   (let ((str (apply 'format format-string args)))
55     (message "%s" (propertize str 'face 'secondary-selection))))
56
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 ;;; Refresh Firefox after save etc
59
60 ;; Partly after an idea on EmacsWiki
61
62 (defvar mozadd-edited-buffer nil)
63 (setq mozadd-edited-buffer nil)
64
65 ;;;###autoload
66 (define-minor-mode mozadd-refresh-edited-on-save-mode
67   "Refresh mozadd edited file in Firefox when saving file.
68 The mozadd edited file is the file in the last buffer visited in
69 `mozadd-mirror-mode'.
70
71 You can use this for example when you edit CSS files.
72
73 The mozadd edited file must be shown in Firefox and visible."
74   :lighter "MozRefresh"
75   (if mozadd-refresh-edited-on-save-mode
76       (add-hook 'after-save-hook 'mozadd-queue-reload-mozilla-edited-file nil t)
77     (remove-hook 'after-save-hook 'mozadd-queue-reload-mozilla-edited-file t)))
78 (put 'mozadd-refresh-edited-on-save-mode 'permanent-local t)
79
80 ;;;###autoload
81 (define-globalized-minor-mode global-mozadd-refresh-edited-on-save-mode
82   mozadd-refresh-edited-on-save-mode
83   (lambda ()
84     (when (or (derived-mode-p 'css-mode)
85               (mozadd-html-buffer-file-p))
86       (mozadd-refresh-edited-on-save-mode 1))))
87
88 (defun mozadd-queue-reload-mozilla-edited-file ()
89   "Reload edited file."
90   (when (buffer-live-p mozadd-edited-buffer)
91     (if (buffer-modified-p mozadd-edited-buffer)
92         (mozadd-warning "Mozadd: Edited buffer %s is not saved, can't reload browser."
93                           (buffer-name mozadd-edited-buffer))
94       (mozadd-add-queue-get-mirror-location)
95       (mozadd-add-task-1 'mozadd-send-refresh-edited-to-mozilla))))
96
97 (defun mozadd-send-refresh-edited-to-mozilla ()
98   "Update the remote mozrepl instance"
99   (with-current-buffer mozadd-edited-buffer
100     (if (not (mozadd-edited-file-is-shown))
101         (mozadd-warning "Mozadd: Edited buffer %s is not shown, can't reload browser."
102                           (buffer-name mozadd-edited-buffer))
103       (comint-send-string (inferior-moz-process)
104                           "setTimeout(BrowserReload(), \"1000\");")))
105   (mozadd-exec-next))
106
107
108 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
109 ;;; Mirror html buffer in Firefox
110
111 ;; Partly after an idea on
112 ;; http://people.internetconnection.net/2009/02/interactive-html-development-in-emacs/
113
114 ;; Fun, it kind of works, but is perhaps totally useless .... - slow
115 ;; and maybe scrolling... - but the file I am testing with have 3000
116 ;; lines...
117
118 ;; Fix-me: How do you get the currently shown page in Firefox?
119
120 (defun mozadd-perhaps-start ()
121   "Start if MozRepl if not running. Return message if not ok."
122   (unless (buffer-live-p inferior-moz-buffer)
123     (condition-case err
124         (progn
125           (inferior-moz-start-process)
126           nil)
127       (error (error-message-string err)))))
128
129 (defvar mozadd-mirror-location nil)
130 (make-variable-buffer-local 'mozadd-mirror-location)
131 (put 'mozadd-mirror-location 'permanent-local t)
132
133 (defvar mozadd-initial-mirror-location nil)
134 (make-variable-buffer-local 'mozadd-initial-mirror-location)
135 (put 'mozadd-initial-mirror-location 'permanent-local t)
136
137 ;;(mozadd-get-comint-string-part "\"hi\" there")
138 (defun mozadd-get-comint-string-part (comint-output)
139   (save-match-data
140     (if (string-match "^\".*?\"" comint-output)
141         (match-string 0 comint-output)
142       comint-output)))
143
144 (defun mozadd-get-initial-mirror-location (comint-output)
145   ;;(message "mozadd-get-initial-mirror-location %S" comint-output)
146   (with-current-buffer mozadd-edited-buffer
147     (setq mozadd-initial-mirror-location (mozadd-get-comint-string-part comint-output)))
148   (mozadd-exec-next)
149   comint-output)
150
151 (defun mozadd-get-mirror-location (comint-output)
152   ;;(message "mozadd-get-mirror-location %S" comint-output)
153   (with-current-buffer mozadd-edited-buffer
154     (setq mozadd-mirror-location (mozadd-get-comint-string-part comint-output)))
155   (mozadd-exec-next)
156   comint-output)
157
158 (defun mozadd-add-queue-get-mirror-location ()
159   (mozadd-add-task "content.location.href" 'mozadd-get-mirror-location))
160
161 (defun mozadd-skip-output-until-prompt (comint-output)
162   ;;(message "mozadd-skip-output-until-prompt %S" comint-output)
163   (if (not (string-match-p "\\(\\w+\\)> $" comint-output))
164       ""
165     ;;(message "done  recieve %s" (current-time-string))
166     (mozadd-exec-next)
167     comint-output
168     ""
169     ))
170
171 (defun mozadd-queue-send-buffer-content-to-mozilla (buffer)
172   (mozadd-add-queue-get-mirror-location)
173   (setq mozadd-edited-buffer buffer)
174   (mozadd-add-task-1 'mozadd-send-buffer-content-to-mozilla))
175
176 (defun mozadd-edited-file-is-shown ()
177   (with-current-buffer mozadd-edited-buffer
178     (string= mozadd-mirror-location mozadd-initial-mirror-location)))
179
180 (defvar mozadd-xml-path-outline-style "2px solid red")
181 (defun mozadd-send-buffer-content-to-mozilla ()
182   "Update the remote mozrepl instance"
183   (with-current-buffer mozadd-edited-buffer
184     (if (mozadd-edited-file-is-shown)
185         (mozadd-requeue-me-as-task
186          (concat "content.document.body.innerHTML="
187                  (json-encode
188                   (save-restriction
189                     (widen)
190                     (let ((where-points nil)
191                           (str "")
192                           (p1 (point-min))
193                           p2)
194                       ;; If nxml-where-mode is on add corresponding outline style.
195                       (when (and (boundp 'nxml-where-mode) nxml-where-mode)
196                         (mapc (lambda (ovl)
197                                 (when (overlay-get ovl 'nxml-where)
198                                   (when (/= ?/ (1+ (char-after (overlay-start ovl))))
199                                     (push (1- (overlay-end ovl)) where-points))))
200                               (overlays-in (point-min) (point-max)))
201                         (setq where-points (sort where-points '<)))
202                       (dolist (p2 where-points)
203                         (setq str (concat str
204                                           (buffer-substring-no-properties p1
205                                                                           p2)))
206                         (setq str (concat str
207                                           " style=\"outline: "
208                                           mozadd-xml-path-outline-style
209                                           "\""))
210                         (setq p1 p2)
211                         )
212                       (setq str (concat str
213                                         (buffer-substring-no-properties p1
214                                                                         (point-max))))
215                       str))
216                   )
217                  ";")
218          'mozadd-skip-output-until-prompt)
219       (mozadd-skip-current-task))
220     ;; Timer to avoid looping
221     (run-with-idle-timer 0 nil 'mozadd-maybe-exec-next)
222     ))
223
224 (defvar mozadd-current-task nil)
225 (setq mozadd-current-task nil)
226
227 (defvar mozadd-task-queue nil)
228 (setq mozadd-task-queue nil)
229 ;;(mozadd-add-task "content.location.href" 'mozadd-get-initial-mirror-location)
230 ;;(mozadd-add-task "hi" 1)
231 ;;(mozadd-add-task "hm" 2)
232
233 (defun mozadd-clear-exec-queue ()
234   (setq mozadd-current-task nil)
235   (setq mozadd-task-queue nil)
236   (when (buffer-live-p inferior-moz-buffer)
237     (with-current-buffer inferior-moz-buffer
238       (dolist (fun (buffer-local-value 'comint-preoutput-filter-functions (current-buffer)))
239         (remove-hook 'comint-preoutput-filter-functions fun t)))))
240
241 (defun mozadd-add-task (input task)
242   (mozadd-add-task-1 (list input task)))
243
244 (defun mozadd-add-task-1 (task)
245   (setq mozadd-task-queue (cons task mozadd-task-queue))
246   (setq mozadd-task-queue (reverse mozadd-task-queue))
247   ;;(message "add-task: mozadd-task-queue=%S, current=%s" mozadd-task-queue mozadd-current-task)
248   (mozadd-maybe-exec-next))
249
250 (defun mozadd-maybe-exec-next ()
251   ;;(message "mozadd-maybe-exec-next, current=%s" mozadd-current-task)
252   (unless mozadd-current-task
253     (mozadd-exec-next)))
254
255 (defun mozadd-exec-next ()
256   (when mozadd-current-task
257     (let* ((old-task mozadd-current-task) ;;(pop mozadd-task-queue))
258            (old-filter (when (listp old-task) (nth 1 old-task))))
259       (when (and old-filter (buffer-live-p inferior-moz-buffer))
260         (with-current-buffer inferior-moz-buffer
261           (remove-hook 'comint-preoutput-filter-functions old-filter t)))))
262   (setq mozadd-current-task nil)
263   (when mozadd-task-queue
264     (let* ((this  (pop mozadd-task-queue))
265            (input (when (listp this) (nth 0 this)))
266            (task  (when (listp this) (nth 1 this)))
267            )
268       (setq mozadd-current-task this)
269       ;;(message "EXEC: %s" this)
270       (if (not (listp this))
271           (funcall this)
272         (when (buffer-live-p inferior-moz-buffer)
273           (with-current-buffer inferior-moz-buffer
274             (add-hook 'comint-preoutput-filter-functions task nil t)))
275         (comint-send-string (inferior-moz-process) input)))))
276
277 (defun mozadd-skip-current-task ()
278   ;;(message "mozadd-skip-current-task")
279   ;;(pop mozadd-task-queue)
280   (setq mozadd-current-task nil))
281
282 (defun mozadd-requeue-me-as-task (input task)
283   (mozadd-skip-current-task)
284   ;;(message "mozadd-requeue-me-as-task %S %S" input task)
285   (setq mozadd-task-queue (cons (list input task) mozadd-task-queue)))
286
287 (defcustom mozadd-browseable-file-extensions
288   '("html" "htm" "xhtml")
289   "File extensions possibly viewable in a web browser."
290   :type '(repeat (string :tag "File extension (without leading dot)"))
291   :group 'mozadd)
292
293 (defun mozadd-html-buffer-file-p ()
294   "Return non-nil if buffer file is viewable in a web browser."
295   (when (buffer-file-name)
296     (member (file-name-extension (buffer-file-name))
297             mozadd-browseable-file-extensions)))
298
299 ;;;###autoload
300 (define-minor-mode mozadd-mirror-mode
301   "Mirror content of current file buffer immediately in Firefox.
302 When you turn on this mode the file will be opened in Firefox.
303 Every change you make in the buffer will trigger a redraw in
304 Firefox - regardless of if you save the file or not.
305
306 For the mirroring to work the edited file must be shown in
307 Firefox and visible.
308
309 If `nxml-where-mode' is on the marks will also be shown in
310 Firefox as CSS outline style.  You can customize the style
311 through the option `mozadd-xml-path-outline-style'.
312
313 See also `mozadd-refresh-edited-on-save-mode'."
314   nil
315   :lighter " MozMirror"
316   :group 'mozadd
317   (if mozadd-mirror-mode
318       (unless (catch 'ok
319                 (unless (mozadd-html-buffer-file-p)
320                   (mozadd-warning "You can only mirror html file buffers")
321                   (throw 'ok nil))
322                 (when (buffer-modified-p)
323                   (mozadd-warning "Please save buffer first")
324                   (throw 'ok nil))
325                 (let ((msg (mozadd-perhaps-start)))
326                   (when msg
327                     (mozadd-warning msg)
328                     (throw 'ok nil)))
329                 (mozadd-clear-exec-queue)
330                 (setq mozadd-edited-buffer (current-buffer))
331                 (mozadd-add-task (concat "content.location.href = "
332                                          "\"file:///" (buffer-file-name) "\";")
333                                  'mozadd-get-initial-mirror-location)
334                 (add-hook 'after-change-functions 'mozadd-update-mozilla t t)
335                 (add-hook 'nxhtml-where-hook 'mozadd-update-mozilla t t)
336                 (add-hook 'post-command-hook 'mozadd-edited-buffer-post-command)
337                 t)
338         (setq mozadd-mirror-mode nil))
339     (setq mozadd-edited-buffer nil)
340     (remove-hook 'post-command-hook 'mozadd-edited-buffer-post-command)
341     (remove-hook 'nxhtml-where-hook 'mozadd-update-mozilla t)
342     (remove-hook 'after-change-functions 'mozadd-update-mozilla t)))
343 (put 'mozadd-mirror-mode 'permanent-local t)
344
345 ;;;###autoload
346 (define-globalized-minor-mode global-mozadd-mirror-mode mozadd-mirror-mode
347   (lambda ()
348     (when (mozadd-html-buffer-file-p)
349       (mozadd-mirror-mode 1))))
350
351 (defun mozadd-edited-buffer-post-command ()
352   "Check if we are in a new edited buffer."
353   (when mozadd-mirror-mode
354     (setq mozadd-edited-buffer (current-buffer))))
355
356
357 (defvar mozadd-buffer-content-to-mozilla-timer nil)
358
359 (defun mozadd-update-mozilla (&rest ignored)
360   (when (timerp mozadd-buffer-content-to-mozilla-timer)
361     (cancel-timer mozadd-buffer-content-to-mozilla-timer))
362   (setq mozadd-buffer-content-to-mozilla-timer
363         (run-with-idle-timer 1 nil 'mozadd-queue-send-buffer-content-to-mozilla (current-buffer))))
364 (put 'mozadd-update-mozilla 'permanent-local-hook t)
365
366
367 (provide 'mozadd)
368 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
369 ;;; mozadd.el ends here