Klimi's new dotfiles with stow.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

131 řádky
5.0 KiB

před 4 roky
  1. ;;; ess-r-xref.el --- An xref backend for R. -*- lexical-binding: t -*-
  2. ;;
  3. ;; Author: Aaron Jacobs
  4. ;; Created: 21 January 2018
  5. ;; Maintainer: ESS-core <ESS-core@r-project.org>
  6. ;;
  7. ;; Keywords: languages, statistics, xref
  8. ;;
  9. ;; This file is part of ESS.
  10. ;;
  11. ;; This file is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 2, or (at your option)
  14. ;; any later version.
  15. ;;
  16. ;; This file is distributed in the hope that it will be useful,
  17. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. ;; GNU General Public License for more details.
  20. ;;
  21. ;; A copy of the GNU General Public License is available at
  22. ;; https://www.r-project.org/Licenses/
  23. ;;; Commentary:
  24. ;; This file contains an xref backend for `ess-r-mode'.
  25. ;;; Code:
  26. (require 'xref)
  27. (require 'ess-inf)
  28. (require 'ess-r-package)
  29. (require 'ess-tracebug)
  30. ;; Silence the byte compiler. OK because this file is only loaded by ess-r-mode.
  31. (declare-function inferior-ess-r-force "ess-r-mode")
  32. (defvar ess-r-xref-pkg-sources nil
  33. "Alist of R package->directory associations.
  34. This variable is used as a cache of package->directory
  35. associations, but could be used by the users for a more refined
  36. control of package locations than `ess-r-package-library-paths'.")
  37. (defun ess-r-xref-backend ()
  38. "An `xref-backend-functions' implementation for `ess-r-mode'.
  39. R's xref backend searches for `ess-r-package-library-paths' when
  40. srcrefs point to temporary locations."
  41. 'ess-r)
  42. (cl-defmethod xref-backend-identifier-at-point ((_backend (eql ess-r)))
  43. (let ((sym (ess-symbol-at-point)))
  44. (when sym
  45. (symbol-name sym))))
  46. (cl-defmethod xref-backend-definitions ((_backend (eql ess-r)) symbol)
  47. (let ((xref (ess-r-xref--xref symbol)))
  48. (when xref
  49. (list xref))))
  50. (cl-defmethod xref-backend-apropos ((_backend (eql ess-r)))
  51. ;; Not yet supported.
  52. nil)
  53. (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql ess-r)))
  54. (inferior-ess-r-force)
  55. (ess-get-words-from-vector ".ess_all_functions()\n"))
  56. (defun ess-r-xref--srcref (symbol)
  57. (inferior-ess-r-force)
  58. ;; Look for `symbol' inside the package namespace
  59. (let* ((pkg (ess-r-package-name))
  60. (pkg (if pkg
  61. (concat "\"" pkg "\"")
  62. "NULL")))
  63. (with-current-buffer (ess-command (format ".ess_srcref(\"%s\", %s)\n" symbol pkg))
  64. (goto-char (point-min))
  65. (when (re-search-forward "(" nil 'noerror)
  66. (goto-char (match-beginning 0))
  67. (read (current-buffer))))))
  68. (defun ess-r-xref--pkg-srcfile (symbol r-src-file)
  69. "Look in the source directory of the R package containing symbol SYMBOL for R-SRC-FILE."
  70. (let* ((env-name (ess-string-command (format ".ess_fn_pkg(\"%s\")\n" symbol)))
  71. (pkg (if (string-equal env-name "")
  72. (user-error "Can't find package for symbol %s" symbol)
  73. env-name))
  74. (dir (or (assoc-default pkg ess-r-xref-pkg-sources)
  75. (cond ((stringp ess-r-package-library-paths)
  76. (expand-file-name pkg ess-r-package-library-paths))
  77. ((listp ess-r-package-library-paths)
  78. (cl-loop for d in ess-r-package-library-paths
  79. for p = (expand-file-name pkg d)
  80. when (file-exists-p p) return p))
  81. (t (user-error "Invalid value of `ess-r-package-library-paths'")))))
  82. (file (when dir (expand-file-name r-src-file dir))))
  83. (when file
  84. (unless (file-readable-p file)
  85. (user-error "Can't read %s" file))
  86. ;; Cache package's source directory.
  87. (unless (assoc pkg ess-r-xref-pkg-sources)
  88. (push `(,pkg . ,dir) ess-r-xref-pkg-sources))
  89. file)))
  90. (defun ess-r-xref--xref (symbol)
  91. "Create an xref for the source file reference of R symbol SYMBOL."
  92. (let ((ref (ess-r-xref--srcref symbol)))
  93. (when ref
  94. (let ((file (nth 0 ref))
  95. (line (nth 1 ref))
  96. (col (nth 2 ref)))
  97. (or
  98. ;; 1) Result of ESS evaluation
  99. (let* ((ess-ref (gethash file ess--srcrefs))
  100. (ess-buff (when ess-ref (ess--dbg-find-buffer (car ess-ref)))))
  101. (when ess-buff
  102. ;; FIXME: this breaks when eval is on larger spans than function
  103. (xref-make symbol (xref-make-buffer-location ess-buff (nth 2 ess-ref)))))
  104. ;; 2) Actual file location
  105. (when (file-readable-p file)
  106. (xref-make symbol (xref-make-file-location file line col)))
  107. ;; 3) Temporary sources - truncate and locate in ess-r-package-library-paths
  108. (when (string-match "/\\(R/.*\\)$" file)
  109. (let ((pkg-file (ess-r-xref--pkg-srcfile symbol (match-string 1 file))))
  110. (when pkg-file
  111. (xref-make symbol (xref-make-file-location
  112. (expand-file-name pkg-file) line col))))))))))
  113. (provide 'ess-r-xref)
  114. ;;; ess-r-xref.el ends here