1 ;;; ess-emcs.el --- simple determination of Emacs/XEmacs and version #.
3 ;; Copyright (C) 2000--2005 A.J. Rossini, Rich M. Heiberger, Martin
4 ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
6 ;; Original Author: A.J. Rossini <rossini@biostat.washington.edu>
7 ;; Created: 07 June 2000
8 ;; Maintainers: ESS-core <ESS-core@stat.math.ethz.ch>
10 ;; Keywords: start up, configuration.
12 ;; This file is part of ESS
14 ;; This file is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2, or (at your option)
19 ;; This file is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to
26 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 ;; This file contains functions for easily determining features of the
31 ;; version of Emacs that we are using. In particular, it look for
32 ;; version number, customize support, as well as Emacs/XEmacs, for
33 ;; flaggin support later on.
37 ;; Older versions of emacs did not have these variables
38 ;; (emacs-major-version and emacs-minor-version.)
39 ;; Let's define them if they're not around, since they make
40 ;; it much easier to conditionalize on the emacs version.
42 (if (and (not (boundp 'emacs-major-version))
43 (string-match "^[0-9]+" emacs-version))
44 (setq emacs-major-version
45 (string-to-int (substring emacs-version
46 (match-beginning 0) (match-end 0)))))
47 (if (and (not (boundp 'emacs-minor-version))
48 (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version))
49 (setq emacs-minor-version
50 (string-to-int (substring emacs-version
51 (match-beginning 1) (match-end 1)))))
53 ;;; Define a function to make it easier to check which version we're
56 (defun ess-running-emacs-version-or-newer (major minor)
57 (or (> emacs-major-version major)
58 (and (= emacs-major-version major)
59 (>= emacs-minor-version minor))))
61 ;(defvar ess-running-xemacs (string-match "XEmacs\\|Lucid" emacs-version))
63 (defvar ess-local-custom-available (featurep 'custom)
64 "Value is nil if custom.el not available, t if available.
65 Only a concern with earlier versions of Emacs.")
67 ;; FIXME: When emacs is started from Cygwin shell in Windows,
68 ;; we have (equal window-system 'x) -and should use "--ess" in *d-r.el
69 (defvar ess-microsoft-p (or (equal window-system 'w32)
71 ;;; (equal (console-type) 'pc)
72 ;;; (equal (console-type) 'mswindows)
73 (equal window-system 'win32)
74 (equal window-system 'mswindows))
75 "Value is t if the OS is one of Microsoft's, nil otherwise.")
78 ;; These definitions are for Emacs versions < 20.4 or XEmacs
79 ;; These are taken verbatim from the file emacs-20.6/lisp/w32-fns.el
81 ;; Note: 20.3 and 19.x NTemacs users are strongly encouraged to upgrade to
82 ;; version 20.4 or higher. NTemacs 20.2 is not supported by ESS.
84 ;; XEmacs 20.x needs this
85 (if (not (fboundp 'find-buffer-visiting))
86 (fset 'find-buffer-visiting 'get-file-buffer))
87 ;; XEmacs <= 21.4.15 needs this
88 (if (not (fboundp 'line-beginning-position))
89 (defalias 'line-beginning-position 'point-at-bol))
91 (if (and (not (featurep 'xemacs))
92 (string-match "XEmacs\\|Lucid" emacs-version))
95 ;; XEmacs 21.x and Emacs 20.x need this
96 (cond ((fboundp 'replace-regexp-in-string)
97 (defalias 'ess-replace-regexp-in-string 'replace-regexp-in-string))
99 (defun ess-replace-regexp-in-string(regexp replace string)
100 "Mimic GNU Emacs function replace-regexp-in-string with XEmacs' replace-in-string"
101 (replace-in-string string regexp replace)))
103 ;; GNU emacs <= 20 -- take Emacs' 21(.3)'s definition:
104 (t (defun ess-replace-regexp-in-string (regexp rep string &optional
105 fixedcase literal subexp start)
106 "Replace all matches for REGEXP with REP in STRING.
108 Return a new string containing the replacements.
110 Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the
111 arguments with the same names of function `replace-match'. If START
112 is non-nil, start replacements at that index in STRING.
114 REP is either a string used as the NEWTEXT arg of `replace-match' or a
115 function. If it is a function it is applied to each match to generate
116 the replacement passed to `replace-match'; the match-data at this
117 point are such that match 0 is the function's argument.
119 To replace only the first match (if any), make REGEXP match up to \\'
120 and replace a sub-expression, e.g.
121 (ess-replace-regexp-in-string \"\\(foo\\).*\\'\" \"bar\" \" foo foo\" nil nil 1)
125 ;; To avoid excessive consing from multiple matches in long strings,
126 ;; don't just call `replace-match' continually. Walk down the
127 ;; string looking for matches of REGEXP and building up a (reversed)
128 ;; list MATCHES. This comprises segments of STRING which weren't
129 ;; matched interspersed with replacements for segments that were.
130 ;; [For a `large' number of replacments it's more efficient to
131 ;; operate in a temporary buffer; we can't tell from the function's
132 ;; args whether to choose the buffer-based implementation, though it
133 ;; might be reasonable to do so for long enough STRING.]
134 (let ((l (length string))
138 (while (and (< start l) (string-match regexp string start))
139 (setq mb (match-beginning 0)
141 ;; If we matched the empty string, make sure we advance by one char
142 (when (= me mb) (setq me (min l (1+ mb))))
143 ;; Generate a replacement for the matched substring.
144 ;; Operate only on the substring to minimize string consing.
145 ;; Set up match data for the substring for replacement;
146 ;; presumably this is likely to be faster than munging the
147 ;; match data directly in Lisp.
148 (string-match regexp (setq str (substring string mb me)))
150 (cons (replace-match (if (stringp rep)
152 (funcall rep (match-string 0 str)))
153 fixedcase literal str subexp)
154 (cons (substring string start mb) ; unmatched prefix
157 ;; Reconstruct a string from the pieces.
158 (setq matches (cons (substring string start l) matches)) ; leftover
159 (apply #'concat (nreverse matches)))))
163 ;; remassoc exists as a built-in function in xemacs, but
166 (if (not (functionp 'remassoc))
167 (defun remassoc (key a)
168 "remove an association pair from an alist"
170 (let ((pair (car a)))
171 (if (equal (car pair) key)
173 (cons pair (remassoc key (cdr a))))))))
175 (if (not (fboundp 'w32-using-nt))
176 (defun w32-using-nt ()
177 "Return non-nil if literally running on Windows NT (i.e., not Windows 9X)."
178 (and (eq system-type 'windows-nt) (getenv "SystemRoot"))))
180 (if (and (featurep 'xemacs)
182 (fboundp 'make-extent)
183 (fboundp 'set-extent-property))
184 (defun ess-xemacs-insert-glyph (gl)
185 "Insert a glyph at the left edge of point."
186 (let ((prop 'myimage) ;; myimage is an arbitrary name, chosen to
187 ;; (hopefully) not conflict with any other
188 ;; properties. Change it if necessary.
190 ;; First, check to see if one of our extents already exists at
191 ;; point. For ease-of-programming, we are creating and using our
192 ;; own extents (multiple extents are allowed to exist/overlap at the
193 ;; same point, and it's quite possible for other applications to
194 ;; embed extents in the current buffer without your knowledge).
195 ;; Basically, if an extent, with the property stored in "prop",
196 ;; exists at point, we assume that it is one of ours, and we re-use
197 ;; it (this is why it is important for the property stored in "prop"
198 ;; to be unique, and only used by us).
199 (if (not (setq extent (extent-at (point) (current-buffer) prop)))
201 ;; If an extent does not already exist, create a zero-length
202 ;; extent, and give it our special property.
203 (setq extent (make-extent (point) (point) (current-buffer)))
204 (set-extent-property extent prop t)
206 ;; Display the glyph by storing it as the extent's "begin-glyph".
207 (set-extent-property extent 'begin-glyph gl))))
209 ;; XEmacs and NTemacs 19.x need these
210 (if (not (boundp 'w32-system-shells))
211 (defvar w32-system-shells '("cmd" "cmd.exe" "command" "command.com"
212 "4nt" "4nt.exe" "4dos" "4dos.exe"
214 "List of strings recognized as Windows NT/9X system shells.")
217 (if (not (fboundp 'w32-system-shell-p))
218 (defun w32-system-shell-p (shell-name)
220 (member (downcase (file-name-nondirectory shell-name))
224 (if (not (fboundp 'w32-shell-name))
225 (defun w32-shell-name ()
226 "Return the name of the shell being used."
227 (or (and (boundp 'explicit-shell-file-name) explicit-shell-file-name)
230 (and (w32-using-nt) "cmd.exe")
234 ;; XEmacs and NTemacs 20.3 need this
235 (if (not (fboundp 'w32-shell-dos-semantics)) (defun w32-shell-dos-semantics ()
236 "Return t if the interactive shell being used expects msdos shell semantics."
237 (or (w32-system-shell-p (w32-shell-name))
238 (and (member (downcase (file-name-nondirectory (w32-shell-name)))
239 '("cmdproxy" "cmdproxy.exe"))
240 (w32-system-shell-p (getenv "COMSPEC")))))
243 ;; XEmacs need this (unless configured with --with-mule=yes)
244 (if (not (boundp 'enable-multibyte-characters))
245 (defvar enable-multibyte-characters nil
246 "Non-nil means the buffer contents are regarded as multi-byte characters.
247 This concept is handled completely differently on Xemacs."))
250 ;; XEmacs on Windows needs this
251 (if (and ess-microsoft-p
252 (not (fboundp 'w32-short-file-name)))
253 (fset 'w32-short-file-name 'win32-short-file-name))
257 \f ; Local variables section
259 ;;; This file is automatically placed in Outline minor mode.
260 ;;; The file is structured as follows:
263 ;;; Subsections: ;;;*;;;
264 ;;; Components: defuns, defvars, defconsts
265 ;;; Random code beginning with a ;;;;* comment
268 ;;; mode: outline-minor
269 ;;; outline-regexp: "\^L\\|\\`;\\|;;\\*\\|;;;\\*\\|(def[cvu]\\|(setq\\|;;;;\\*"
272 ;;; ess-emcs.el ends here