1 ;;; as-external.el --- Emacs as an external editor to other apps
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
11 ;; Features that might be required by this library:
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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
24 ;; See variable `as-external-mode' for more information.
27 ;;; A note on the implementation:
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:
33 ;; 1. The choice made must override other possible choices.
35 ;; 2. Beside the file name the implementation here also checks if the
36 ;; buffer has clients waiting. That makes the check more reliable.
38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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.
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.
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.
60 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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))
76 (defgroup as-external nil
77 "Settings related to Emacs as external editor."
81 (defcustom as-external-its-all-text-regexp "/itsalltext/"
82 "Regular expression matching It's All Text buffer's file."
86 (defcustom as-external-alist
88 ("/itsalltext/.*wiki" as-external-for-wiki)
89 ("/itsalltext/.*mail" as-external-for-mail-mode)
90 ("/itsalltext/" as-external-for-xhtml)
92 "List to determine setup if Emacs is used as an external Editor.
93 Element in this list should have the form
95 \(FILE-REGEXP BUFFER-SETUP)
97 where FILE-REGEXP should be a regular expression to match
98 `buffer-file-name'. If it matches then BUFFER-SETUP should be
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'.
108 The list is processed by `as-external-setup'. Note that the first
111 The default entries in this list supports for Firefox addon It's
114 - `as-external-for-xhtml'. For text areas on web pages where you
115 can enter some XHTML code, for example blog comment fields.
117 - `as-external-for-mail-mode', for editing web mail messages.
119 - `as-external-for-wiki', for mediawiki.
121 See also `as-external-mode'."
123 (list (choice (variable :tag "Regexp variable")
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)
135 (defun as-external-fall-back (msg)
136 "Fallback to text-mode if necessary."
138 (lwarn t :warning "%s. Using text-mode" msg))
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
145 See URL `https://addons.mozilla.org/en-US/firefox/addon/4125'.
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:
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.
156 Also bypass the question for line end conversion when using
159 (if (not (fboundp 'nxhtml-mode))
160 (as-external-fall-back "Can't find nXhtml")
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))))
173 (defvar as-external-mail-mode-comment-pattern "^>.*$"
174 "Regular expression for a comment line.")
176 (defvar as-external-mail-mode-email-pattern
177 (concat "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*"
179 "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}")
180 "Regular expression for a mail address.")
182 (defvar as-external-mail-mode-font-lock-keywords
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))
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 >).
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
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)
208 (wrap-to-fill-column-mode 1))
211 (defun as-external-for-wiki ()
212 "Setup for Firefox addon It's All Text to edit MediaWikis."
214 (require 'wikipedia-mode nil t)
215 (if (not (featurep 'wikipedia-mode))
216 (as-external-fall-back "Can't find file wikipedia-mode.el")
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.
228 This can for example be useful when blogging or writing comments
231 See `as-external-alist' for more information."
234 ;;(modify-coding-system-alist 'file "/itsalltext/" as-external-its-all-text-coding)
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)
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))))
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'."
254 (as-external-setup-1)
255 (error (message "as-external-setup error: %s" err))))
257 (defvar as-external-my-frame nil)
258 (make-variable-buffer-local 'as-external-my-frame)
260 (defvar as-external-last-buffer nil)
262 (defun as-external-server-window-fix-frames ()
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
269 (dolist (f (frame-list))
270 (unless (eq f as-external-my-frame)
272 (raise-frame as-external-my-frame)))
273 (error (message "%s" (error-message-string err)))))
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)))
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))))
287 (= 1 (length (window-list as-external-my-frame 'no-mini))))
288 (delete-frame as-external-my-frame)
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))
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))
306 (throw 'done t)))))))
308 (provide 'as-external)
309 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;;; as-external.el ends here