mywin: use whitespace-line-column to calculate number of parallel windows
[emacs-init.git] / nxhtml / util / as-external.el
1 ;;; as-external.el --- Emacs as an external editor to other apps
2 ;;
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Created: Mon Jun 25 19:02:49 2007
5 (defconst as-external:version "0.6") ;;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 ;;   None
14 ;;
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16 ;;
17 ;;; Commentary:
18 ;;
19 ;;  This little library should make it easier to use Emacs as an
20 ;;  external editor in certain cases. One such case is when want to
21 ;;  use Emacs as the external editor with the Firefox add-on "It's All
22 ;;  Text".
23 ;;
24 ;;  See variable `as-external-mode' for more information.
25 ;;
26 ;;
27 ;;; A note on the implementation:
28 ;;
29 ;; You may wonder why this does not use `auto-mode-alist' since it
30 ;; checks the file name in nearly the same way? It is perhaps possible
31 ;; to use that, but there are two things to be aware of:
32 ;;
33 ;; 1. The choice made must override other possible choices.
34 ;;
35 ;; 2. Beside the file name the implementation here also checks if the
36 ;;    buffer has clients waiting. That makes the check more reliable.
37 ;;
38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
39 ;;
40 ;;; Change log:
41 ;;
42 ;;
43 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 ;;
45 ;; This program is free software; you can redistribute it and/or
46 ;; modify it under the terms of the GNU General Public License as
47 ;; published by the Free Software Foundation; either version 2, or
48 ;; (at your option) any later version.
49 ;;
50 ;; This program is distributed in the hope that it will be useful,
51 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
52 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
53 ;; General Public License for more details.
54 ;;
55 ;; You should have received a copy of the GNU General Public License
56 ;; along with this program; see the file COPYING.  If not, write to
57 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
58 ;; Floor, Boston, MA 02110-1301, USA.
59 ;;
60 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
61 ;;
62 ;;; Code:
63
64 (eval-when-compile (require 'cl))
65 (eval-when-compile (require 'html-write nil t))
66 (eval-when-compile (require 'mlinks nil t))
67 (eval-when-compile (require 'mumamo nil t))
68 (eval-when-compile (require 'nxhtml-mode nil t))
69 (eval-when-compile (require 'ourcomments-util nil t))
70 (eval-when-compile (require 'pause nil t))
71 (eval-when-compile (require 'server))
72 (eval-when-compile (require 'wikipedia-mode nil t))
73 (eval-and-compile  (require 'wrap-to-fill nil t))
74
75 ;;;###autoload
76 (defgroup as-external nil
77   "Settings related to Emacs as external editor."
78   :group 'nxhtml
79   :group 'external)
80
81 (defcustom as-external-its-all-text-regexp "/itsalltext/"
82   "Regular expression matching It's All Text buffer's file."
83   :type 'regexp
84   :group 'as-external)
85
86 (defcustom as-external-alist
87   '(
88     ("/itsalltext/.*wiki" as-external-for-wiki)
89     ("/itsalltext/.*mail" as-external-for-mail-mode)
90     ("/itsalltext/"       as-external-for-xhtml)
91    )
92   "List to determine setup if Emacs is used as an external Editor.
93 Element in this list should have the form
94
95   \(FILE-REGEXP BUFFER-SETUP)
96
97 where FILE-REGEXP should be a regular expression to match
98 `buffer-file-name'. If it matches then BUFFER-SETUP should be
99 called in the buffer.
100
101 * Tip when using Firefox's add-on It's All Text: It looks like
102   the file name used will be constructed from the host url. For
103   example if your are editing something on
104   http://www.emacswiki.org/ the file name may be something like
105   'www.emacswiki.org.283b1y212e.html'.
106
107
108 The list is processed by `as-external-setup'. Note that the first
109 match is used!
110
111 The default entries in this list supports for Firefox addon It's
112 All Text:
113
114 - `as-external-for-xhtml'.  For text areas on web pages where you
115   can enter some XHTML code, for example blog comment fields.
116
117 - `as-external-for-mail-mode', for editing web mail messages.
118
119 - `as-external-for-wiki', for mediawiki.
120
121 See also `as-external-mode'."
122   :type '(repeat
123           (list (choice (variable :tag "Regexp variable")
124                         regexp)
125                 command))
126   :group 'as-external)
127
128 (defcustom as-external-its-all-text-coding 'utf-8
129   "Coding system to use for It's All Text buffers.
130 See also `as-external-for-xhtml'."
131   :type '(choice (const :tag "No special coding system" nil)
132                  coding-system)
133   :group 'as-external)
134
135 (defun as-external-fall-back (msg)
136   "Fallback to text-mode if necessary."
137   (text-mode)
138   (lwarn t :warning "%s. Using text-mode" msg))
139
140 ;;;###autoload
141 (defun as-external-for-xhtml ()
142   "Setup for Firefox addon It's All Text to edit XHTML.
143 It's All Text is a Firefox add-on for editing textareas with an
144 external editor.
145 See URL `https://addons.mozilla.org/en-US/firefox/addon/4125'.
146
147 In this case Emacs is used to edit textarea fields on a web page.
148 The text will most often be part of a web page later, like on a
149 blog.  Therefore turn on these:
150
151 - `nxhtml-mode' since some XHTML tags may be allowed.
152 - `nxhtml-validation-header-mode' since it is not a full page.
153 - `wrap-to-fill-column-mode' to see what you are writing.
154 - `html-write-mode' to see it even better.
155
156 Also bypass the question for line end conversion when using
157 emacsw32-eol."
158   (interactive)
159   (if (not (fboundp 'nxhtml-mode))
160       (as-external-fall-back "Can't find nXhtml")
161     (nxhtml-mode)
162     (nxhtml-validation-header-mode 1)
163     (set (make-local-variable 'wrap-to-fill-left-marg-modes)
164          '(nxhtml-mode fundamental-mode))
165     (wrap-to-fill-column-mode 1)
166     ;;(visible-point-mode 1)
167     (when (fboundp 'html-write-mode) (html-write-mode 1))
168     (when (boundp 'emacsw32-eol-ask-before-save)
169       (make-local-variable 'emacsw32-eol-ask-before-save)
170       (setq emacsw32-eol-ask-before-save nil))))
171
172
173 (defvar as-external-mail-mode-comment-pattern "^>.*$"
174   "Regular expression for a comment line.")
175
176 (defvar as-external-mail-mode-email-pattern
177   (concat "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*"
178           "\@"
179           "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}")
180   "Regular expression for a mail address.")
181
182 (defvar as-external-mail-mode-font-lock-keywords
183   (list
184    (list as-external-mail-mode-comment-pattern
185          '(0 font-lock-comment-face))
186    ;; (list as-external-mail-mode-email-pattern
187    ;;       '(0 font-lock-keyword-face))
188    ))
189
190 ;;;###autoload
191 (define-derived-mode as-external-for-mail-mode text-mode "ExtMail "
192   "Setup for Firefox addon It's All Text to edit mail.
193 Set normal mail comment markers in column 1 (ie >).
194
195 Set `fill-column' to 90 and enable `wrap-to-fill-column-mode' so
196 that it will look similar to how it will look in the sent plain
197 text mail.
198
199 See also `as-external-mode'."
200   ;; To-do: Look at http://globs.org/articles.php?lng=en&pg=2
201   (set (make-local-variable 'comment-column) 0)
202   (set (make-local-variable 'comment-start) ">")
203   (set (make-local-variable 'comment-end)   "")
204   (set (make-local-variable 'font-lock-defaults)
205        '((as-external-mail-mode-font-lock-keywords) nil))
206   (setq fill-column 90)
207   (mlinks-mode 1)
208   (wrap-to-fill-column-mode 1))
209
210 ;;;###autoload
211 (defun as-external-for-wiki ()
212   "Setup for Firefox addon It's All Text to edit MediaWikis."
213   (interactive)
214   (require 'wikipedia-mode nil t)
215   (if (not (featurep 'wikipedia-mode))
216       (as-external-fall-back "Can't find file wikipedia-mode.el")
217     (wikipedia-mode)))
218
219
220 ;;;###autoload
221 (define-minor-mode as-external-mode
222   "If non-nil check if Emacs is called as external editor.
223 When Emacs is called as an external editor for example to edit
224 text areas on a web page viewed with Firefox this library tries
225 to help to setup the buffer in a useful way. It may for example
226 set major and minor modes for the buffer.
227
228 This can for example be useful when blogging or writing comments
229 on blogs.
230
231 See `as-external-alist' for more information."
232   :global t
233   :group 'as-external
234   ;;(modify-coding-system-alist 'file "/itsalltext/" as-external-its-all-text-coding)
235   (let ((coding-entry
236          (cons
237           as-external-its-all-text-regexp
238           (cons as-external-its-all-text-coding
239                 as-external-its-all-text-coding))))
240     ;;(message "as-external-mode=%s" as-external-mode)
241     (if as-external-mode
242         (progn
243           (add-to-list 'file-coding-system-alist coding-entry)
244           (add-hook 'server-visit-hook 'as-external-setup t))
245       (setq file-coding-system-alist
246             (delq coding-entry file-coding-system-alist))
247       (remove-hook 'server-visit-hook 'as-external-setup))))
248
249 (defun as-external-setup ()
250   "Check if Emacs is used as an external editor.
251 If so then turn on useful major and minor modes.
252 This is done by checking `as-external-alist'."
253   (condition-case err
254       (as-external-setup-1)
255     (error (message "as-external-setup error: %s" err))))
256
257 (defvar as-external-my-frame nil)
258 (make-variable-buffer-local 'as-external-my-frame)
259
260 (defvar as-external-last-buffer nil)
261
262 (defun as-external-server-window-fix-frames ()
263   (condition-case err
264       (with-current-buffer as-external-last-buffer
265         (unless (buffer-live-p pause-buffer)
266           (remove-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames)
267           (setq as-external-my-frame (or as-external-my-frame
268                                          (make-frame)))
269           (dolist (f (frame-list))
270             (unless (eq f as-external-my-frame)
271               (lower-frame f)))
272           (raise-frame as-external-my-frame)))
273     (error (message "%s" (error-message-string err)))))
274
275 (defun as-external-server-window (buffer)
276   (setq server-window nil)
277   (with-current-buffer buffer
278     (setq as-external-last-buffer (current-buffer))
279     (run-with-idle-timer 2 nil 'as-external-server-window-fix-frames)
280     (add-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames)
281     (add-hook 'kill-buffer-hook 'as-external-delete-my-frame nil t)))
282
283 (defun as-external-delete-my-frame ()
284   (let ((win (and (frame-live-p as-external-my-frame)
285                   (get-buffer-window nil as-external-my-frame))))
286     (when (and win
287                (= 1 (length (window-list as-external-my-frame 'no-mini))))
288       (delete-frame as-external-my-frame)
289       (lower-frame))))
290
291 (defun as-external-setup-1 ()
292   ;; Fix-me: How does one know if the file names are case sensitive?
293   (unless (when (boundp 'nowait) nowait) ;; dynamically bound in `server-visit-files'
294     (unless server-window
295       ;; `server-goto-toplevel' has been done here.
296       ;; Setup to use a new frame
297       (setq server-window 'as-external-server-window))
298     (catch 'done
299       (dolist (rec as-external-alist)
300         (let ((file-regexp (car rec))
301               (setup-fun   (cadr rec)))
302           (when (symbolp file-regexp)
303             (setq file-regexp (symbol-value file-regexp)))
304           (when (string-match file-regexp (buffer-file-name))
305             (funcall setup-fun)
306             (throw 'done t)))))))
307
308 (provide 'as-external)
309 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;;; as-external.el ends here