Klimi's new dotfiles with stow.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

1057 行
42 KiB

  1. ;;; ess-utils.el --- General Emacs utility functions used by ESS -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 1998--2010 A.J. Rossini, Richard M. Heiberger, Martin
  3. ;; Maechler, Kurt Hornik, Rodney Sparapani, and Stephen Eglen.
  4. ;; Copyright (C) 2011--2017 A.J. Rossini, Richard M. Heiberger, Martin Maechler,
  5. ;; Kurt Hornik, Rodney Sparapani, Stephen Eglen and Vitalie Spinu.
  6. ;; Author: Martin Maechler <maechler@stat.math.ethz.ch>
  7. ;; Created: 9 Sept 1998
  8. ;; Maintainer: ESS-core <ESS-core@r-project.org>
  9. ;; This file is part of ESS (Emacs Speaks Statistics).
  10. ;; This file is free software; you can redistribute it and/or modify
  11. ;; it under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  14. ;; This file is distributed in the hope that it will be useful,
  15. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;; GNU General Public License for more details.
  18. ;; A copy of the GNU General Public License is available at
  19. ;; https://www.r-project.org/Licenses/
  20. ;;; Commentary:
  21. ;; Various utilities for ESS.
  22. ;;; Code:
  23. (require 'cl-lib)
  24. (require 'comint)
  25. (eval-when-compile
  26. (require 'tramp))
  27. ;; The only ESS file this file should depend on is ess-custom.el
  28. (require 'ess-custom)
  29. (defvar ac-modes)
  30. (declare-function ess-eval-linewise "ess-inf" (text &optional invisibly eob even-empty wait-last-prompt sleep-sec wait-sec))
  31. (declare-function color-lighten-name "color" (name percent))
  32. (declare-function tramp-dissect-file-name "tramp" (name &optional nodefault))
  33. ;; The following declares can be removed once we drop Emacs 25
  34. (declare-function tramp-file-name-method "tramp")
  35. (declare-function tramp-file-name-user "tramp")
  36. (declare-function tramp-file-name-host "tramp")
  37. (declare-function tramp-file-name-localname "tramp")
  38. (declare-function tramp-file-name-hop "tramp")
  39. ;;*;; elisp tools
  40. (defun ess-next-code-line (&optional arg skip-to-eob)
  41. "Move ARG lines of code forward (backward if ARG is negative).
  42. If `ess-eval-empty' is non-nil, skip past all empty and comment
  43. lines. ARG is 1 by default. If ARG is 0 only comments are skipped
  44. forward. Don't skip the last empty and comment lines in the
  45. buffer unless SKIP-TO-EOB is non-nil. On success, return 0.
  46. Otherwise go as far as possible and return -1."
  47. (interactive "p")
  48. (if (or ess-eval-empty
  49. (and (fboundp 'ess-roxy-entry-p)
  50. (ess-roxy-entry-p)))
  51. (forward-line arg)
  52. (setq arg (or arg 1))
  53. (beginning-of-line)
  54. (let ((pos (point))
  55. (inc (if (>= arg 0) 1 -1))
  56. (cnt (if (= arg 0) 1 arg))
  57. (out 0))
  58. ;; when orig-arg == 0, we skip only comments
  59. (while (and (/= cnt 0) (= out 0))
  60. (unless (= arg 0)
  61. (setq out (forward-line inc))) ; out==0 means success
  62. (comment-beginning)
  63. (beginning-of-line)
  64. (forward-comment (* inc (buffer-size))) ;; as suggested in info file
  65. (if (or skip-to-eob
  66. (not (looking-at ess-no-skip-regexp))) ;; don't go to eob or whatever
  67. (setq cnt (- cnt inc))
  68. (goto-char pos)
  69. (setq cnt 0)
  70. (forward-line inc)) ;; stop at next empty line
  71. (setq pos (point)))
  72. (goto-char pos)
  73. out)))
  74. (defun ess-goto-line (line)
  75. "Go to LINE in the widened buffer."
  76. (save-restriction
  77. (widen)
  78. (goto-char (point-min))
  79. (forward-line (1- line))))
  80. (defun ess-skip-thing (thing)
  81. "Leave point at the end of THING.
  82. THING can be 'function, 'paragraph, or 'line."
  83. (cond
  84. ((eql thing 'line) (goto-char (line-end-position)))
  85. ((eql thing 'paragraph) (forward-paragraph))
  86. ((eql thing 'function) (end-of-defun) (skip-chars-backward " \t\n"))))
  87. (defun ess-search-except (regexp &optional except backward)
  88. "Search for a REGEXP and store as match 1.
  89. Optionally ignore strings that match EXCEPT. If BACKWARD is
  90. non-nil, search backward."
  91. (let ((continue t) (exit nil))
  92. (while continue
  93. (if (or (and backward (search-backward-regexp regexp nil t))
  94. (and (not backward) (search-forward-regexp regexp nil t)))
  95. (progn
  96. (setq exit (match-string 1))
  97. (setq continue (and except (string-match except exit)))
  98. (if continue (setq exit nil)))
  99. ;;else
  100. (setq continue nil)))
  101. exit))
  102. (defun ess-save-and-set-local-variables ()
  103. "If buffer was modified, save file and set Local Variables if defined.
  104. Return t if buffer was modified, nil otherwise."
  105. (let ((ess-temp-return-value (buffer-modified-p)))
  106. (save-buffer)
  107. (hack-local-variables)
  108. ess-temp-return-value))
  109. (defun ess-get-file-or-buffer (file-or-buffer)
  110. "Return FILE-OR-BUFFER if it is a buffer.
  111. Otherwise return the buffer associated with the file which must
  112. be qualified by it's path; if the buffer does not exist, return
  113. nil."
  114. (declare (side-effect-free t)
  115. (obsolete nil "ESS 19.04"))
  116. (if (bufferp file-or-buffer)
  117. file-or-buffer
  118. (find-buffer-visiting file-or-buffer)))
  119. (defun ess-file-content (file)
  120. "Return the content of FILE as string."
  121. (if (file-exists-p file)
  122. (with-temp-buffer
  123. (insert-file-contents-literally file)
  124. (buffer-string))
  125. (error "File '%s' does not exist" file)))
  126. (defun ess-uniq (list predicate)
  127. "Uniquify LIST, stably, deleting elements using PREDICATE.
  128. Return the list with subsequent duplicate items removed by side effects.
  129. PREDICATE is called with an element of LIST and a list of elements from LIST,
  130. and should return the list of elements with occurrences of the element removed.
  131. This function will work even if LIST is unsorted. See also `delete-dups'."
  132. (declare (obsolete 'delete-dups "ESS 19.04"))
  133. (let ((list list))
  134. (while list
  135. (setq list (setcdr list (funcall predicate (car list) (cdr list))))))
  136. list)
  137. (define-obsolete-function-alias 'ess-uniq-list 'delete-dups "ESS 19.04")
  138. (defalias 'ess-flatten-list
  139. ;; `flatten-tree' is a function in Emacs 27
  140. (if (fboundp 'flatten-tree)
  141. 'flatten-tree
  142. (lambda (list)
  143. "Take the arguments and flatten them into one long LIST.
  144. Drops 'nil' entries."
  145. ;; Taken from lpr.el
  146. ;; `lpr-flatten-list' is defined here (copied from "message.el" and
  147. ;; enhanced to handle dotted pairs as well) until we can get some
  148. ;; sensible autoloads, or `flatten-list' gets put somewhere decent.
  149. (ess-flatten-list-1 list))))
  150. (defun ess-flatten-list-1 (list)
  151. "Internal helper for `ess-flatten-list', which see for LIST."
  152. (cond
  153. ((null list) (list))
  154. ((consp list)
  155. (append (ess-flatten-list-1 (car list))
  156. (ess-flatten-list-1 (cdr list))))
  157. (t (list list))))
  158. (define-obsolete-function-alias 'ess-delete-blank-lines
  159. 'delete-blank-lines "ESS 19.04")
  160. (define-obsolete-function-alias 'ess-line-to-list-of-words #'split-string "ESS 19.04")
  161. ;;*;; System
  162. (defun ess-revert-wisely ()
  163. "Revert from disk if file and buffer last modification times are different."
  164. (interactive)
  165. ;; whether or not a revert is needed, force load local variables
  166. ;; for example, suppose that you change the local variables and then
  167. ;; save the file, a revert is unneeded, but a force load is
  168. (hack-local-variables)
  169. (unless (verify-visited-file-modtime (current-buffer))
  170. (progn
  171. (let ((ess-temp-store-point (point)))
  172. (revert-buffer t t)
  173. (goto-char ess-temp-store-point))
  174. t)))
  175. (define-obsolete-function-alias 'ess-find-exec 'ess-find-exec-completions "ESS 19.04")
  176. (defun ess-find-exec-completions (root)
  177. "Given the ROOT of an executable file name, find all possible completions.
  178. Search for the executables in the variable `exec-path'."
  179. (let (executables)
  180. (dolist (dir exec-path)
  181. (when (and (> (length dir) 0)
  182. (file-accessible-directory-p dir))
  183. ;; the first test above excludes "" from exec-path, which can be
  184. ;; problematic with Tramp.
  185. (dolist (f (file-name-all-completions root dir))
  186. (setq f (expand-file-name f dir))
  187. (when (and (file-executable-p f)
  188. (not (backup-file-name-p f))
  189. (not (file-directory-p f)))
  190. (push f executables)))))
  191. executables))
  192. (defun ess-drop-non-directories (file-strings)
  193. "Drop all entries in FILE-STRINGS that do not \"look like\" directories."
  194. (ess-flatten-list (mapcar 'file-name-directory file-strings)))
  195. (defun ess--parent-dir (path n)
  196. "Return Nth parent of PATH."
  197. (let ((opath path))
  198. (while (and path (> n 0))
  199. (setq path (file-name-directory (directory-file-name opath)))
  200. (if (equal path opath)
  201. (setq path nil)
  202. (setq opath path
  203. n (1- n))))
  204. path))
  205. ;;*;; Interaction with inferiors
  206. (defmacro ess-when-new-input (time-var &rest body)
  207. "BODY is evaluate only if the value of process variable TIME-VAR
  208. is bigger than the time of the last user input (stored in
  209. `last-eval' process variable). TIME-VAR is the name of the
  210. process variable which holds the access time. See the code for
  211. `ess-synchronize-dirs' and `ess-cache-search-list'.
  212. Returns nil when no current process, or process is busy, or
  213. time-var > last-eval. Otherwise, execute BODY and return the last
  214. value.
  215. If BODY is executed, set process variable TIME-VAR
  216. to (current-time).
  217. Variable *proc* is bound to the current process during the
  218. evaluation of BODY.
  219. Should be used in `ess-idle-timer-functions' which call the
  220. process to avoid excessive requests."
  221. (declare (indent 1) (debug t))
  222. `(with-ess-process-buffer 'no-error
  223. (let ((le (process-get *proc* 'last-eval))
  224. (tv (process-get *proc* ',time-var)))
  225. (when (and (or (null tv) (null le) (time-less-p tv le))
  226. (not (process-get *proc* 'busy)))
  227. (let ((out (progn ,@body)))
  228. (process-put *proc* ',time-var (current-time))
  229. out)))))
  230. ;;; Emacs Integration
  231. (defun ess-derived-mode-p ()
  232. "Non-nil if the current major mode is an ESS major mode."
  233. (or (derived-mode-p 'ess-mode)
  234. (derived-mode-p 'ess-julia-mode)))
  235. (defun ess--generate-eval-visibly-submenu (_menu)
  236. '(["yes" (lambda () (interactive) (setq ess-eval-visibly t))
  237. :style radio :enable t :selected (eq ess-eval-visibly t)]
  238. ["nowait" (lambda () (interactive) (setq ess-eval-visibly 'nowait))
  239. :style radio :enable t :selected (eq ess-eval-visibly 'nowait) ]
  240. ["no" (lambda () (interactive) (setq ess-eval-visibly nil))
  241. :style radio :enable t :selected (eq ess-eval-visibly nil) ]))
  242. ;; Font Lock
  243. (defun ess--fl-keywords-values ()
  244. "Return a cons (STANDARD-VALUE . CUSTOM-VALUE) of `ess-font-lock-keywords'."
  245. (let ((sym ess-font-lock-keywords))
  246. (if (and (symbolp sym)
  247. (custom-variable-p sym))
  248. (cons
  249. (eval (car (get sym 'standard-value)))
  250. (symbol-value sym))
  251. (error "`ess-font-lock-keywords' must be a symbol of a custom variable"))))
  252. (defun ess--extract-fl-keywords ()
  253. (let ((values (ess--fl-keywords-values)))
  254. (mapcar (lambda (kv)
  255. (let ((cust-kv (assoc (car kv) (cdr values))))
  256. (when cust-kv
  257. (setcdr kv (cdr cust-kv))))
  258. kv)
  259. (copy-alist (car values)))))
  260. (defun ess-build-font-lock-keywords ()
  261. "Retrieve `font-lock-keywords' from ess-[dialect]-font-lock-keywords.
  262. Merge the customized values of that variable on top of the
  263. standard values and return the new list. For this to work,
  264. `ess-font-lock-keywords' should be a name of the
  265. ess-[dialect]-font-lock-keywords variable."
  266. (delq nil
  267. (mapcar (lambda (c)
  268. (when (cdr c)
  269. (symbol-value (car c))))
  270. (ess--extract-fl-keywords))))
  271. (defun ess-font-lock-toggle-keyword (keyword)
  272. "Toggle KEYWORD font-lock."
  273. (interactive
  274. (list (intern (ess-completing-read
  275. "Keyword to toggle"
  276. (mapcar (lambda (el) (symbol-name (car el)))
  277. (car (ess--fl-keywords-values)))
  278. nil t))))
  279. (let* ((values (ess--fl-keywords-values))
  280. (kwd (cond
  281. ;; already in custom values
  282. ((assoc keyword (cdr values)))
  283. ;; if keyword is not already in custom values (can happen if
  284. ;; we add new keywords but the user has the old value saved in
  285. ;; .emacs-custom.el)
  286. ((let ((kwd (assoc keyword (car values)))
  287. (sym ess-font-lock-keywords))
  288. (when kwd
  289. (set sym (cons kwd (symbol-value sym)))
  290. kwd)))
  291. (t (error "Invalid keyword %s" keyword)))))
  292. (setcdr kwd (not (cdr kwd)))
  293. (let ((mode major-mode)
  294. (dialect ess-dialect))
  295. ;; refresh font-lock defaults in all relevant buffers
  296. (mapc (lambda (b)
  297. (with-current-buffer b
  298. (when (and (eq major-mode mode)
  299. (eq ess-dialect dialect))
  300. (font-lock-refresh-defaults))))
  301. (buffer-list)))))
  302. (defun ess--generate-font-lock-submenu (_menu)
  303. "Generate ESS font-lock submenu."
  304. (append (mapcar (lambda (el)
  305. `[,(symbol-name (car el))
  306. (lambda () (interactive)
  307. (ess-font-lock-toggle-keyword ',(car el)))
  308. :style toggle
  309. :enable t
  310. :selected ,(cdr el)])
  311. (ess--extract-fl-keywords))
  312. (list "-----"
  313. ["Save to custom"
  314. (lambda () (interactive)
  315. (customize-save-variable ess-font-lock-keywords
  316. (ess--extract-fl-keywords)))
  317. t])))
  318. ;;; External modes
  319. ;; Define these here for the byte compiler since ido dynamically
  320. ;; let-binds them:
  321. (defvar ido-choice-list)
  322. (defvar ido-context-switch-command)
  323. (defvar ido-directory-too-big)
  324. (defvar ido-directory-nonreadable)
  325. (defvar ido-current-directory)
  326. (defvar ido-enable-flex-matching)
  327. (declare-function ido-read-internal "ido" (item prompt hist &optional default require-match initial))
  328. (defun ess-completing-read (prompt collection &optional predicate
  329. require-match initial-input hist def)
  330. "Read a string in the minibuffer, with completion.
  331. Use `ido-completing-read' if IDO interface is present, or fall
  332. back on classical `completing-read' otherwise. Meaning of PROMPT,
  333. COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT, HIST, and
  334. DEF is as in `completing-read'. PROMPT is automatically suffixed
  335. with ': ' and (default %s) when needed. If HIST is nil use
  336. `ess--completing-hist' as history. See also `ess-use-ido'."
  337. (let ((use-ido (and ess-use-ido (require 'ido nil t))))
  338. (setq hist (or hist 'ess--completing-hist))
  339. (when (and def (not use-ido)) ;; ido places in front and highlights the default
  340. (setq prompt (format "%s(default %s)" prompt def)))
  341. (setq prompt (concat prompt ": "))
  342. (if use-ido
  343. (let ((reset-ido (and use-ido (not ido-mode))) ;people not using ido but having it)
  344. (ido-current-directory nil)
  345. (ido-directory-nonreadable nil)
  346. (ido-directory-too-big nil)
  347. (ido-context-switch-command 'ignore)
  348. (ido-enable-flex-matching ess-ido-flex-matching) ;it's fast and useful, may be get into options
  349. (ido-choice-list (copy-sequence collection)) ;ido removes the match (reported)
  350. sel)
  351. (unwind-protect
  352. (progn
  353. (add-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
  354. (add-hook 'choose-completion-string-functions 'ido-choose-completion-string)
  355. (setq sel (ido-read-internal 'list prompt hist def require-match initial-input))
  356. (when hist ;; ido does not push into hist the whole match if C-SPC or RET is used (reported)
  357. (unless (string= sel (car (symbol-value hist)))
  358. (set hist (cons sel (symbol-value hist))))))
  359. (when reset-ido
  360. (remove-hook 'minibuffer-setup-hook 'ido-minibuffer-setup)
  361. (remove-hook 'choose-completion-string-functions 'ido-choose-completion-string)))
  362. sel)
  363. ;; else usual completion
  364. (completing-read prompt collection predicate require-match initial-input hist def))))
  365. (defun ess--setup-auto-complete (sources &optional inferior)
  366. "Setup auto-complete depending on user settings.
  367. SOURCES gets added to `ac-sources', INFERIOR should be t for
  368. inferior buffers."
  369. ;; auto-complete
  370. (when (and (boundp 'ac-sources)
  371. (if inferior
  372. (eq ess-use-auto-complete t)
  373. ess-use-auto-complete))
  374. (add-to-list 'ac-modes major-mode)
  375. ;; files should be in front; ugly, but needed
  376. (setq ac-sources
  377. (delq 'ac-source-filename ac-sources))
  378. (mapc (lambda (el) (add-to-list 'ac-sources el))
  379. sources)
  380. (add-to-list 'ac-sources 'ac-source-filename)))
  381. (defun ess--setup-company (sources &optional inferior)
  382. "Setup company depending on user settings.
  383. SOURCES gets added to `company-backends', and when t, INFERIOR
  384. specifies inferior buffers."
  385. ;; company
  386. (when (and (boundp 'company-backends)
  387. (if inferior
  388. (eq ess-use-company t)
  389. ess-use-company))
  390. (setq-local company-backends
  391. (cl-copy-list (append sources company-backends)))
  392. (delq 'company-capf company-backends)))
  393. (defmacro ess--execute-electric-command (map &optional prompt wait exit-form &rest args)
  394. "Execute single-key commands defined in MAP till a key is pressed which is not part of map.
  395. Single-key input commands are those that once executed do not
  396. require the prefix command for subsequent invocation. Return the
  397. value of the lastly executed command. PROMPT is passed to
  398. `read-event'.
  399. If WAIT is t, wait for next input and ignore the keystroke which
  400. triggered the command.
  401. Each command in map should accept one at least one argument, the
  402. most recent event (as read by `read-event'). ARGS are the
  403. supplementary arguments passed to the commands.
  404. EXIT-FORM should be supplied for a more refined control of the
  405. read-even loop. The loop is exited when EXIT-FORM evaluates to
  406. t. See examples in the tracebug code."
  407. ;;VS[09-06-2013]: check: it seems that set-temporary-overlay-map is designed
  408. ;;for this type of things; see also repeat.el package.
  409. `(let* ((ev last-command-event)
  410. (command (lookup-key ,map (vector ev)))
  411. out exit )
  412. (if (not (or ,wait command))
  413. (message "%s is undefined" (key-description (this-command-keys)))
  414. (unless ,wait
  415. (setq out (and command (funcall command ev ,@args))))
  416. (while (and (not exit)
  417. (setq command
  418. (lookup-key ,map
  419. (vector (setq ev (read-event ,prompt))))))
  420. (setq out (funcall command ev ,@args))
  421. (sleep-for .01)
  422. (setq exit ,exit-form))
  423. (unless exit ;; push only if an event triggered the exit
  424. (push ev unread-command-events))
  425. out)))
  426. (cl-defgeneric ess-build-tags-command ()
  427. "Command passed to generate tags.
  428. If nil, `ess-build-tags-for-directory' uses the mode's imenu
  429. expression. Otherwise, it should be a string with two %s
  430. formats: one for directory and another for the output file."
  431. nil)
  432. ;;; Emacs itself
  433. (defun ess-yank-cleaned-commands ()
  434. "Yank and strip the code, leaving only (R/S/Lsp/..) commands.
  435. Deletes any lines not beginning with a prompt, and then removes
  436. the prompt from those lines that remain. Invoke this command with
  437. \\[universal-argument] \\[universal-argument] \\<ess-mode-map>\\[yank]."
  438. (setq yank-window-start (window-start))
  439. (let ((beg (point)))
  440. (push-mark beg)
  441. (setq this-command t)
  442. (insert-for-yank (current-kill 0))
  443. (when (and (require 'ess-trns) (fboundp 'ess-transcript-clean-region))
  444. (ess-transcript-clean-region beg (point) nil))
  445. (if (eq (point) beg)
  446. (message "No commands found"))
  447. (if (eq this-command t)
  448. (setq this-command 'yank))))
  449. (defun ess-yank (&optional arg)
  450. "Call `ess-yank-cleaned-commands' if ARG is 16.
  451. With double prefix ARG (\\[universal-argument]
  452. \\[universal-argument]) call `ess-yank-cleaned-commands'."
  453. (interactive "*P")
  454. (if (equal '(16) arg)
  455. (ess-yank-cleaned-commands)
  456. (let* ((remapped (command-remapping 'yank (point)))
  457. (command (cond ((eq remapped 'ess-yank) 'yank)
  458. ((null remapped) 'yank)
  459. (t remapped))))
  460. (funcall command arg))))
  461. (put 'ess-yank 'delete-selection 'yank)
  462. (defun ess-build-tags-for-directory (dir tagfile)
  463. "Ask for directory and tag file and build tags for current dialect.
  464. If the current language defines `ess-build-tags-command' use it
  465. and ask the subprocess to build the tags. Otherwise use imenu
  466. regexp and call find .. | etags .. in a shell command. You must
  467. have 'find' and 'etags' programs installed.
  468. Use M-. to navigate to a tag. \\[visit-tags-table] to
  469. append/replace the currently used tag table.
  470. If prefix is given, force tag generation based on imenu. Might be
  471. useful when different language files are also present in the
  472. directory (.cpp, .c etc)."
  473. (interactive "DDirectory to tag:
  474. GTags file (default TAGS): ")
  475. (when (or (eq (length (file-name-nondirectory tagfile)) 0)
  476. (file-directory-p tagfile))
  477. (setq tagfile (concat (file-name-as-directory tagfile) "TAGS")))
  478. ;; Emacs find-tags doesn't play well with remote TAG files :(
  479. (when (file-remote-p tagfile)
  480. (require 'tramp)
  481. (setq tagfile (with-parsed-tramp-file-name tagfile foo foo-localname)))
  482. (when (file-remote-p dir)
  483. (require 'tramp)
  484. (setq dir (with-parsed-tramp-file-name dir foo foo-localname)))
  485. (if (and (ess-build-tags-command) (null current-prefix-arg))
  486. (ess-eval-linewise (format (ess-build-tags-command) dir tagfile))
  487. ;; else generate from imenu
  488. (unless imenu-generic-expression
  489. (error "No ess-tag-command found, and no imenu-generic-expression defined"))
  490. (let* ((find-cmd
  491. (format "find %s -type f -size 1M \\( -regex \".*\\.\\(cpp\\|jl\\|[RsrSch]\\(nw\\)?\\)$\" \\)" dir))
  492. (regs (delq nil (mapcar (lambda (l)
  493. (if (string-match "'" (cadr l))
  494. nil ;; remove for time being
  495. (format "/%s/\\%d/"
  496. (replace-regexp-in-string "/" "\\/" (nth 1 l) t)
  497. (nth 2 l))))
  498. imenu-generic-expression)))
  499. (tags-cmd (format "etags -o %s --regex='%s' -" tagfile
  500. (mapconcat 'identity regs "' --regex='"))))
  501. (message "Building tags: %s" tagfile)
  502. (when (= 0 (shell-command (format "%s | %s" find-cmd tags-cmd)))
  503. (message "Building tags .. ok!")))))
  504. ;;; UI
  505. (defvar ess-current-region-overlay
  506. (let ((overlay (make-overlay (point) (point))))
  507. (overlay-put overlay 'face 'highlight)
  508. overlay)
  509. "The overlay for highlighting currently evaluated region or line.")
  510. (defun ess-blink-region (start end)
  511. "Blink from START to END depending on option `ess-blink-region'."
  512. (when ess-blink-region
  513. (move-overlay ess-current-region-overlay start end)
  514. (run-with-timer ess-blink-delay nil
  515. (lambda ()
  516. (delete-overlay ess-current-region-overlay)))))
  517. (defun ess-deactivate-mark ()
  518. "Deactivate the mark, if active.
  519. If `evil-mode' is on, switch to `evil-normal-state'."
  520. (if (and (bound-and-true-p evil-mode)
  521. (fboundp 'evil-visual-state-p)
  522. (evil-visual-state-p))
  523. (when (fboundp 'evil-normal-state)
  524. (evil-normal-state))
  525. (when mark-active
  526. (deactivate-mark))))
  527. ;; SJE: 2009-01-30 -- this contribution from
  528. ;; Erik Iverson <iverson@biostat.wisc.edu>
  529. (defun ess-tooltip-show-at-point (text xo yo)
  530. "Show a tooltip displaying TEXT at (around) point.
  531. XO and YO are x- and y-offsets for the toolbar from point."
  532. (let (
  533. (fx (frame-parameter nil 'left))
  534. (fy (frame-parameter nil 'top))
  535. (fw (frame-pixel-width))
  536. (fh (frame-pixel-height))
  537. frame-left frame-top my-x-offset my-y-offset)
  538. ;; The following comment was found before code looking much like that
  539. ;; of frame-left and frame-top below in the file
  540. ;; tooltip-help.el. I include it here for acknowledgment, and I did observe
  541. ;; the same behavior with the Emacs window maximized under Windows XP.
  542. ;; -----original comment--------
  543. ;; handles the case where (frame-parameter nil 'top) or
  544. ;; (frame-parameter nil 'left) return something like (+ -4).
  545. ;; This was the case where e.g. Emacs window is maximized, at
  546. ;; least on Windows XP. The handling code is "shamelessly
  547. ;; stolen" from cedet/speedbar/dframe.el
  548. ;; (contributed by Andrey Grigoriev)
  549. (setq frame-left (if (not (consp fx))
  550. fx
  551. (if (eq (car fx) '-)
  552. (- (display-pixel-width) (car (cdr fx)) fw)
  553. (car (cdr fx)))))
  554. (setq frame-top (if (not (consp fy))
  555. fy
  556. (if (eq (car fy) '-)
  557. (- (display-pixel-height) (car (cdr fy)) fh)
  558. (car (cdr fy)))))
  559. ;; calculate the offset from point, use xo and yo to adjust to preference
  560. (setq my-x-offset (+ (car(window-inside-pixel-edges))
  561. (car(posn-x-y (posn-at-point)))
  562. frame-left xo))
  563. (setq my-y-offset (+ (cadr(window-inside-pixel-edges))
  564. (cdr(posn-x-y (posn-at-point)))
  565. frame-top yo))
  566. (let ((tooltip-frame-parameters
  567. (cons (cons 'top my-y-offset)
  568. (cons (cons 'left my-x-offset)
  569. tooltip-frame-parameters))))
  570. (tooltip-show text))))
  571. (defun ess-select-frame-set-input-focus (frame)
  572. "Select FRAME, raise it, and set input focus, if possible.
  573. Copied almost verbatim from gnus-utils.el (but with test for mac added)."
  574. ;; The function `select-frame-set-input-focus' won't set
  575. ;; the input focus under Emacs 21.2 and X window system.
  576. ;;((fboundp 'select-frame-set-input-focus)
  577. ;; (defalias 'gnus-select-frame-set-input-focus
  578. ;; 'select-frame-set-input-focus)
  579. ;; (select-frame-set-input-focus frame))
  580. (raise-frame frame)
  581. (select-frame frame)
  582. (cond ((and
  583. (memq window-system '(x mac))
  584. (fboundp 'x-focus-frame))
  585. (x-focus-frame frame))
  586. ((and (eq window-system 'w32)
  587. ;; silence byte compiler warnings about w32-fns
  588. (fboundp 'w32-focus-frame))
  589. (w32-focus-frame frame)))
  590. (when focus-follows-mouse
  591. (set-mouse-position frame (1- (frame-width frame)) 0)))
  592. (define-obsolete-function-alias 'ess-do-auto-fill 'do-auto-fill "ESS 19.04")
  593. ;;; Syntax
  594. (defun ess-containing-sexp-position ()
  595. "Return the `cadr' of `syntax-ppss'."
  596. (cadr (syntax-ppss)))
  597. (defun ess-code-end-position ()
  598. "Like (line-end-position) but stops at comments."
  599. (save-excursion
  600. (goto-char (1+ (line-end-position)))
  601. (forward-comment -1)
  602. (point)))
  603. ;; FIXME: The following function pattern stuff is specific to R but is
  604. ;; used throughout ESS
  605. (defvar ess-r-set-function-start
  606. ;; [MGAR].. <=> {setMethod(), set[Group]Generic(), setAs(), setReplaceMethod()}
  607. ;; see also set-S4-exp in ess-r-function-pattern below
  608. "^set[MGAR][GMa-z]+\\s-?(")
  609. (defvar ess-function-pattern nil ; in R set to ess-r-function-pattern
  610. "Regexp to match the beginning of a function in S buffers.")
  611. (defvar ess-r-symbol-pattern
  612. "\\(\\sw\\|\\s_\\)"
  613. "The regular expression for matching an R symbol.")
  614. (defvar ess-r-name-pattern
  615. (concat "\\(" ess-r-symbol-pattern "+\\|\\(`\\).+`\\)")
  616. "The regular expression for matching a R name.")
  617. (defvar ess--r-s-function-pattern
  618. (let* ((Q "\\s\"") ; quote
  619. (Sym-0 "\\(\\sw\\|\\s_\\)") ; symbol
  620. (Symb (concat Sym-0 "+"))
  621. (xSymb "[^ \t\n\"']+") ;; (concat "\\[?\\[?" Sym-0 "*")); symbol / [ / [[ / [symbol / [[symbol
  622. ;; FIXME: allow '%foo%' but only when quoted; don't allow [_0-9] at beg.
  623. (space "\\(\\s-\\|\n\\)*") ; white space
  624. (part-1 (concat
  625. "\\(" ;;--------outer Either-------
  626. "\\(\\(" ; EITHER
  627. Q xSymb Q ; any function name between quotes
  628. "\\)\\|\\("
  629. Symb ; (beginning of name) + ess-r-symbol-pattern
  630. "\\)\\)")) ; END EITHER OR
  631. (set-S4-exp
  632. (concat
  633. "^set\\(As\\|Method\\|Generic\\|GroupGeneric\\|ReplaceMethod\\)(" ; S4 ...
  634. Q xSymb Q "," space
  635. ;; and now often `` signature(......), : ''
  636. ".*" ;; <<< FIXME ???
  637. ))
  638. (part-2 (concat
  639. "\\|" ;;--------outer Or ---------
  640. set-S4-exp
  641. "\\)" ;;--------end outer Either/Or-------
  642. "\\(" space "\\s<.*\\s>\\)*" ; whitespace, comment
  643. ;; FIXME: in principle we should skip 'definition *= *' here
  644. space "function\\s-*(" ; whitespace, function keyword, parenthesis
  645. )))
  646. `(,part-1 ,part-2))
  647. "Placeholder for use in constructing `ess-r-function-pattern' and `ess-s-function-pattern'.")
  648. (defvar ess-r-function-pattern
  649. (concat (car ess--r-s-function-pattern)
  650. "\\s-*\\(<-\\|=\\)" ; whitespace, assign
  651. (nth 1 ess--r-s-function-pattern))
  652. "The regular expression for matching the beginning of an R function.")
  653. (defvar ess-s-function-pattern
  654. (concat (car ess--r-s-function-pattern)
  655. "\\s-*\\(<-\\|_\\|=\\)" ; whitespace, assign (incl. "_")
  656. (nth 1 ess--r-s-function-pattern))
  657. "The regular expression for matching the beginning of an S function.")
  658. (defvar ess--fn-name-start-cache nil)
  659. (defun ess--fn-name-start ()
  660. "Return (FN-NAME . START-POS).
  661. FN-NAME is a function name located before the pointer. START-POS
  662. is the position where FN-NAME starts. Store this cons in variable
  663. `ess--fn-name-start-cache'."
  664. (save-excursion
  665. (save-restriction
  666. (let* ((proc (get-buffer-process (current-buffer)))
  667. (mark (and proc (process-mark proc))))
  668. (if (and mark (>= (point) mark))
  669. (narrow-to-region mark (point)))
  670. (and (fboundp 'ess-noweb-narrow-to-chunk)
  671. (bound-and-true-p ess-noweb-mode)
  672. (ess-noweb-narrow-to-chunk))
  673. (unless (ess-inside-string-p)
  674. (setq ess--fn-name-start-cache
  675. (condition-case nil ;; check if it is inside a function
  676. (progn
  677. ;; for the sake of big buffers, look only 1000 chars back
  678. (narrow-to-region (max (point-min) (- (point) 1000)) (point))
  679. (up-list -1)
  680. (while (not (looking-at "("))
  681. (up-list -1))
  682. (let ((funname (symbol-name (ess-symbol-at-point))))
  683. (when (and funname
  684. (not (member funname ess-S-non-functions)))
  685. (cons funname (- (point) (length funname))))))
  686. (error nil))))))))
  687. (defun ess-symbol-at-point ()
  688. "Like `symbol-at-point' but consider fully qualified names.
  689. Fully qualified names include accessor symbols (like aaa$bbb and
  690. aaa@bbb in R)."
  691. (with-syntax-table (or ess-mode-completion-syntax-table
  692. (syntax-table))
  693. (symbol-at-point)))
  694. (defun ess-bounds-of-symbol ()
  695. "Get bounds of symbol at point.
  696. Intended for completion."
  697. (let ((bounds (with-syntax-table (or ess-mode-completion-syntax-table
  698. (syntax-table))
  699. (bounds-of-thing-at-point 'symbol))))
  700. (and bounds
  701. (not (save-excursion
  702. (goto-char (car bounds))
  703. (looking-at "/\\|.[0-9]")))
  704. bounds)))
  705. (defun ess-symbol-start ()
  706. "Get initial position for objects completion.
  707. Symbols are fully qualified names that include accessor
  708. symbols (like aaa$bbb and aaa@bbb in R)."
  709. (car (ess-bounds-of-symbol)))
  710. (defun ess-arg-start ()
  711. "Get initial position for args completion."
  712. (when (not (ess-inside-string-p))
  713. (when (ess--fn-name-start)
  714. (if (looking-back "[(,]+[ \t\n]*" nil)
  715. (point)
  716. (ess-symbol-start)))))
  717. (defun ess-inside-string-p (&optional pos)
  718. "Return non-nil if POS is inside string.
  719. POS defaults to `point'."
  720. (let ((pos (or pos (point))))
  721. (nth 3 (syntax-ppss pos))))
  722. (defun ess-inside-comment-p (&optional pos)
  723. "Return non-nil if POS is inside string.
  724. POS defaults to `point'."
  725. (let ((pos (or pos (point))))
  726. (nth 4 (syntax-ppss pos))))
  727. (defun ess-inside-string-or-comment-p (&optional pos)
  728. "Return non-nil if POS is inside a string or comment.
  729. POS defaults to `point'."
  730. (or (ess-inside-string-p pos)
  731. (ess-inside-comment-p pos)))
  732. (defun ess-inside-brackets-p (&optional pos curly?)
  733. "Return t if position POS is inside brackets.
  734. POS defaults to point if no value is given. If CURLY?? is non nil
  735. also return t if inside curly brackets."
  736. (save-excursion
  737. (let ((ppss (syntax-ppss pos))
  738. (r nil))
  739. (while (and (> (nth 0 ppss) 0)
  740. (not r))
  741. (goto-char (nth 1 ppss))
  742. (when (or (char-equal ?\[ (char-after))
  743. (and curly?
  744. (char-equal ?\{ (char-after))))
  745. (setq r t))
  746. (setq ppss (syntax-ppss)))
  747. r)))
  748. ;;; String manipulation
  749. (defun ess-quote-special-chars (string)
  750. "Quote special characters in STRING."
  751. (replace-regexp-in-string
  752. "\"" "\\\\\\&"
  753. (replace-regexp-in-string ;; replace backslashes
  754. "\\\\" "\\\\" string nil t)))
  755. (defun ess-rep-regexp (regexp to-string &optional fixedcase literal verbose)
  756. "Instead of (replace-regexp..) -- do NOT replace in strings or comments.
  757. If FIXEDCASE is non-nil, do *not* alter case of replacement text.
  758. If LITERAL is non-nil, do *not* treat `\\' as special.
  759. If VERBOSE is non-nil, (message ..) about replacements."
  760. (let ((case-fold-search (and case-fold-search
  761. (not fixedcase))); t <==> ignore case in search
  762. (ppt (point)); previous point
  763. (p))
  764. (while (and (setq p (re-search-forward regexp nil t))
  765. (< ppt p))
  766. (setq ppt p)
  767. (cond ((not (ess-inside-string-or-comment-p (1- p)))
  768. (if verbose
  769. (let ((beg (match-beginning 0)))
  770. (message "buffer in (match-beg.,p)=(%d,%d) is '%s'"
  771. beg p (buffer-substring beg p))))
  772. (replace-match to-string fixedcase literal))))))
  773. (defun ess-replace-regexp-dump-to-src (regexp to-string &optional dont-query verbose)
  774. "Replace REGEXP matches from beginning of buffer with TO-STRING.
  775. If DONT-QUERY is non-nil, call `ess-rep-regexp' else call
  776. `query-replace-regexp'. VERBOSE can be passed to `ess-rep-regexp'."
  777. (save-excursion
  778. (goto-char (point-min))
  779. (if dont-query
  780. (ess-rep-regexp regexp to-string nil nil verbose)
  781. (query-replace-regexp regexp to-string nil))))
  782. (defun ess-space-around (word &optional from verbose)
  783. "Replace-regexp .. ensuring space around all occurrences of WORD.
  784. Start at from FROM, which defaults to point."
  785. (interactive "d\nP"); Defaults: point and prefix (C-u)
  786. (save-excursion
  787. (goto-char from)
  788. (ess-rep-regexp (concat "\\([^ \t\n]\\)\\(\\<" word "\\>\\)")
  789. "\\1 \\2" nil nil verbose)
  790. (goto-char from)
  791. (ess-rep-regexp (concat "\\(\\<" word "\\>\\)\\([^ \t\n]\\)")
  792. "\\1 \\2" nil nil verbose)))
  793. (defun ess-time-string (&optional clock)
  794. "Return a string for use as a timestamp, like \"13 Mar 1992\".
  795. Include hr:min if CLOCK is non-nil. Redefine to taste."
  796. (declare (obsolete format-time-string "ESS 19.04"))
  797. (format-time-string (concat "%e %b %Y" (if clock ", %H:%M"))))
  798. (defun ess-replace-in-string (str regexp newtext &optional literal)
  799. "Replace all matches in STR for REGEXP with NEWTEXT string.
  800. Optional LITERAL non-nil means do a literal replacement.
  801. Otherwise treat \\ in NEWTEXT string as special:
  802. \\& means substitute original matched text,
  803. \\N means substitute match for \(...\) number N,
  804. \\\\ means insert one \\."
  805. (if (not (stringp str))
  806. (error "(replace-in-string): First argument must be a string: %s" str))
  807. (if (stringp newtext)
  808. nil
  809. (error "(replace-in-string): 3rd arg must be a string: %s"
  810. newtext))
  811. (let ((rtn-str "")
  812. (start 0)
  813. (special)
  814. match prev-start)
  815. (while (setq match (string-match regexp str start))
  816. (setq prev-start start
  817. start (match-end 0)
  818. rtn-str
  819. (concat
  820. rtn-str
  821. (substring str prev-start match)
  822. (cond (literal newtext)
  823. (t (mapconcat
  824. (function
  825. (lambda (c)
  826. (if special
  827. (progn
  828. (setq special nil)
  829. (cond ((eq c ?\\) "\\")
  830. ((eq c ?&)
  831. (substring str
  832. (match-beginning 0)
  833. (match-end 0)))
  834. ((and (>= c ?0) (<= c ?9))
  835. (if (> c (+ ?0 (length
  836. (match-data))))
  837. ;; Invalid match num
  838. (error "(replace-in-string) Invalid match num: %c" c)
  839. (setq c (- c ?0))
  840. (substring str
  841. (match-beginning c)
  842. (match-end c))))
  843. (t (char-to-string c))))
  844. (if (eq c ?\\) (progn (setq special t) nil)
  845. (char-to-string c)))))
  846. newtext ""))))))
  847. (concat rtn-str (substring str start))))
  848. ;;- From: friedman@gnu.ai.mit.edu (Noah Friedman)
  849. ;;- Date: 12 Feb 1995 21:30:56 -0500
  850. ;;- Newsgroups: gnu.emacs.sources
  851. ;;- Subject: nuke-trailing-whitespace
  852. ;;-
  853. ;;- This is too trivial to make into a big todo with comments and copyright
  854. ;;- notices whose length exceed the size of the actual code, so consider it
  855. ;;- public domain. Its purpose is along similar lines to that of
  856. ;;- `require-final-newline', which is built in. I hope the names make it
  857. ;;- obvious.
  858. ;; (add-hook 'write-file-hooks 'nuke-trailing-whitespace)
  859. ;;or at least
  860. ;; (add-hook 'ess-mode-hook
  861. ;; (lambda ()
  862. ;; (add-hook 'local-write-file-hooks 'nuke-trailing-whitespace)))
  863. (defvar ess-nuke-trailing-whitespace-p nil;disabled by default 'ask
  864. "[Dis]activates (ess-nuke-trailing-whitespace).
  865. Disabled if nil; if t, it works unconditionally, otherwise,
  866. the user is queried.
  867. Note that setting the default to t may not be a good idea when you edit
  868. binary files!")
  869. ;;; MM: Newer Emacsen now have delete-trailing-whitespace
  870. ;;; -- but no customization like nuke-trailing-whitespace-p ..
  871. (defun ess-nuke-trailing-whitespace ()
  872. "Nuke all trailing whitespace in the buffer.
  873. Whitespace in this case is just spaces or tabs. This is a useful
  874. function to put on `write-file-hooks'. If the variable
  875. `ess-nuke-trailing-whitespace-p' is nil, this function is
  876. disabled. If t, unreservedly strip trailing whitespace. If not
  877. nil and not t, query for each instance."
  878. (interactive)
  879. (let ((bname (buffer-name)))
  880. (cond ((or
  881. (string= major-mode "rmail-mode")
  882. (string= bname "RMAIL")
  883. nil)); do nothing..
  884. (t
  885. (and (not buffer-read-only)
  886. ess-nuke-trailing-whitespace-p
  887. (save-match-data
  888. (save-excursion
  889. (save-restriction
  890. (widen)
  891. (goto-char (point-min))
  892. (cond ((eq ess-nuke-trailing-whitespace-p t)
  893. (while (re-search-forward "[ \t]+$" (point-max) t)
  894. (delete-region (match-beginning 0)
  895. (match-end 0))))
  896. (t
  897. (query-replace-regexp "[ \t]+$" "")))))))))
  898. ;; always return nil, in case this is on write-file-hooks.
  899. nil))
  900. ;;; Debugging tools
  901. (defun ess-write-to-dribble-buffer (text)
  902. "Write TEXT to `ess-dribble-buffer'."
  903. (when (or ess-verbose ess-write-to-dribble)
  904. (with-current-buffer (get-buffer-create ess-dribble-buffer)
  905. (goto-char (point-max))
  906. (insert-before-markers text))))
  907. (defun ess-if-verbose-write (text)
  908. "Write TEXT to `ess-dribble-buffer' only if `ess-verbose' is non-nil."
  909. (when ess-verbose (ess-write-to-dribble-buffer text)))
  910. (defun ess-kill-last-line ()
  911. (save-excursion
  912. (goto-char (point-max))
  913. (forward-line -1)
  914. (delete-region (point-at-eol) (point-max))))
  915. (defun ess-sleep ()
  916. "Put Emacs to sleep for `ess-sleep-for-shell' seconds (floats work)."
  917. (sleep-for ess-sleep-for-shell))
  918. (defun ess-setq-vars-local (alist &optional buf)
  919. "Set language variables from ALIST, in buffer BUF, if desired."
  920. (when buf (set-buffer buf))
  921. (mapc (lambda (pair)
  922. (make-local-variable (car pair))
  923. (set (car pair) (eval (cdr pair)))
  924. (when (bound-and-true-p ess--make-local-vars-permanent)
  925. (put (car pair) 'permanent-local t))) ;; hack for Rnw
  926. alist))
  927. (defvar ess-error-regexp "^\\(Syntax error: .*\\) at line \\([0-9]*\\), file \\(.*\\)$"
  928. "Regexp to search for errors.")
  929. (define-obsolete-function-alias 'ess-beginning-of-function 'beginning-of-defun "ESS 19.04")
  930. (define-obsolete-function-alias 'ess-end-of-function 'end-of-defun "ESS 19.04")
  931. (provide 'ess-utils)
  932. ;;; ess-utils.el ends here