PageRenderTime 35ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/SN-NG4.1/snavigator/etc/sn.el

https://gitlab.com/OpenSourceMirror/sourcenav
Emacs Lisp | 312 lines | 190 code | 36 blank | 86 comment | 6 complexity | 12acc6eb9783b6637b0c68b07302c8a5 MD5 | raw file
  1. ;;; sn.el -- Source Navigator interface for Emacs
  2. ;;; Copyright (C) 1997 Cygnus Solutions
  3. ;;; Known problems and things to do:
  4. ;;; * SN tags workalike should work by making phony tags file and
  5. ;;; using tags-table-format-hooks. Then we'd get all the tags
  6. ;;; functionality for free.
  7. ;;; * Should stick a function on find-file-hook that asks each SN
  8. ;;; session if the new file is part of the session.
  9. ;;; Constants.
  10. ;; non-nil if using XEmacs.
  11. (defconst sn-is-xemacs (string-match "XEmacs" emacs-version))
  12. ;;; Variable definitions.
  13. ;; History list for tags finding.
  14. (defvar sn-history-list nil)
  15. ;; This holds the connection to SN. It is local to each buffer; this
  16. ;; lets us have multiple SN projects share an Emacs.
  17. (defvar sn-process nil)
  18. (make-variable-buffer-local 'sn-process)
  19. ;; Name of the current process. This is only set when running a
  20. ;; function from a process filter. It is only defvar'd because I
  21. ;; don't like to use variables that aren't declared.
  22. (defvar sn-current-process nil)
  23. (defvar sn-minor-mode nil "t if source navigator mode is active")
  24. (make-variable-buffer-local 'sn-minor-mode)
  25. (or (assoc 'sn-minor-mode minor-mode-alist)
  26. (setq minor-mode-alist (cons '(sn-minor-mode " SN") minor-mode-alist)))
  27. (setplist 'sn-minor-mode (plist-put (symbol-plist 'sn-minor-mode)
  28. 'permanent-local t))
  29. (defun sn-minor-mode (arg)
  30. "Minor mode for working with Source Navigator.
  31. Adds some commands for looking up stuff in SN:
  32. \\{sn-keymap}
  33. This mode is automatically activated when files are opened by SN and cannot
  34. be activated for other buffers. You can toggle it for SN-related buffers
  35. though. This lets you access the command bindings that this mode overrides."
  36. (interactive "P")
  37. (unless sn-process
  38. (error "This buffer has no Source Navigator connection"))
  39. (setq sn-minor-mode (if (null arg) (not sn-minor-mode)
  40. (> (prefix-numeric-value arg) 0))))
  41. ;; When we tell SN about a file, we must always send it exactly the
  42. ;; same name as it sent us. So we stash the original filename here.
  43. (defvar sn-file-name nil)
  44. (make-variable-buffer-local 'sn-file-name)
  45. (defvar sn-keymap nil
  46. "Keymap for Source Navigator minor mode.")
  47. (unless sn-keymap
  48. (setq sn-keymap (make-sparse-keymap))
  49. (define-key sn-keymap "\M-." 'sn-find-tag)
  50. (define-key sn-keymap "\C-x4." 'sn-tag-unimplemented)
  51. (define-key sn-keymap "\C-x5." 'sn-tag-unimplemented)
  52. (define-key sn-keymap "\M-," 'sn-tag-unimplemented)
  53. (define-key sn-keymap "\M-\t" 'sn-tag-unimplemented)
  54. (define-key sn-keymap "\C-c.c" 'sn-classbrowser)
  55. (define-key sn-keymap "\C-c.h" 'sn-classtree)
  56. (define-key sn-keymap "\C-c.r" 'sn-retrieve)
  57. (define-key sn-keymap "\C-c.x" 'sn-xref)
  58. (cond (sn-is-xemacs
  59. (define-key sn-keymap '(meta control ?.) 'sn-tag-unimplemented))
  60. ;; GNU Emacs.
  61. (t (define-key sn-keymap [\M-\C-.] 'sn-tag-unimplemented))))
  62. (or (assoc 'sn-minor-mode minor-mode-map-alist)
  63. (setq minor-mode-map-alist (cons (cons 'sn-minor-mode sn-keymap)
  64. minor-mode-map-alist)))
  65. ;;;
  66. ;;; Commands that the user can run to interact with SN.
  67. ;;;
  68. ;; Hide the current project.
  69. (defun sn-hide-project ()
  70. "Hide the Source Navigator project associated with this buffer."
  71. (interactive)
  72. (sn-send "tkbHideShow withdraw"))
  73. ;; Like find-tag, but use SN to look up the tag.
  74. (defun sn-find-tag (tagname)
  75. "Like find-tag, but use Source Navigator to look up name."
  76. (interactive
  77. (progn
  78. (require 'etags)
  79. (list (read-string "Find tag: "
  80. (find-tag-default)
  81. 'sn-history-list))))
  82. (sn-send (concat "sn_emacs_display_object "
  83. (sn-tcl-quote tagname)))
  84. ;; We know a response is coming. This makes things look a little
  85. ;; more synchronous.
  86. (accept-process-output))
  87. (defun sn-classbrowser (class)
  88. "Browse the contents of a class in the Source Navigator."
  89. (interactive
  90. (progn
  91. (require 'etags)
  92. (list (read-string "Browse class: "
  93. (find-tag-default)
  94. 'sn-history-list))))
  95. (sn-send (concat "sn_classbrowser " (sn-tcl-quote class))))
  96. (defun sn-classtree (class)
  97. "Browse a class in the Source Navigator hierarchy browser."
  98. (interactive
  99. (progn
  100. (require 'etags)
  101. (list (read-string "Browse class: "
  102. (find-tag-default)
  103. 'sn-history-list))))
  104. (sn-send (concat "sn_classtree " (sn-tcl-quote class))))
  105. (defun sn-retrieve (pattern)
  106. "Tell Source Navigator to retrieve all symbols matching pattern.
  107. If there is only one match SN will take Emacs there. If there are
  108. several they are listed in a pop-up where you can select one to edit."
  109. (interactive
  110. (progn
  111. (require 'etags)
  112. (list (read-string "Retrieve pattern: "
  113. (find-tag-default)
  114. 'sn-history-list))))
  115. (sn-send (concat "sn_retrieve_symbol " (sn-tcl-quote pattern) " all")))
  116. (defun sn-xref (symbol)
  117. "Look up a symbol in the Source Navigator cross-referencer."
  118. (interactive
  119. (progn
  120. (require 'etags)
  121. (list (read-string "Xref symbol: "
  122. (find-tag-default)
  123. 'sn-history-list))))
  124. (sn-send (concat "sn_xref both " (sn-tcl-quote symbol))))
  125. (defun sn-tag-unimplemented ()
  126. "Bound to tags-finding keys that Source Navigator can't (yet) handle."
  127. (interactive)
  128. (error "this keybinding is unimplemented in Source Navigator"))
  129. ;; find-tag-other-frame and find-tag-other-window versions are harder
  130. ;; to do; there is a synchronization problem here.
  131. ;; (defun sn-find-tag-other-frame)
  132. ;;(defun sn-find-tag-other-window)
  133. ;; (defun sn-find-tag-regexp) ; FIXME do it?
  134. ;; FIXME what about tags-query-replace, tags-loop-continue,
  135. ;; tags-search, tags-table-files, find-tag-hook, find-tag-noselect?
  136. ;; Turn off menus for now. Why bother when there is only one item?
  137. ; (progn
  138. ; (define-key sn-keymap [menu-bar SN] (cons "SN" (make-sparse-keymap)))
  139. ; (define-key sn-keymap [menu-bar SN hide] '("Hide project"
  140. ; . sn-hide-project)))
  141. ; )
  142. ;;;
  143. ;;; Internal functions that can talk to SN.
  144. ;;;
  145. ;; Connect to Source Navigator. Arguments are:
  146. ;; * TMPFILENAME - a temp file containing some lisp code; remove it
  147. ;; here. This can be nil, meaning no file exists.
  148. ;; * HOSTNAME - name of host to connect to
  149. ;; * DIRECTORY - directory where temp file might be (if not absolute)
  150. ;; * PORT - port to connect to
  151. (defun sn-startup (tmpfilename hostname directory port)
  152. (save-excursion
  153. (let ((buffer (generate-new-buffer " sn")))
  154. (set-buffer buffer)
  155. (setq sn-process (open-network-stream "sn" buffer hostname port))
  156. (process-kill-without-query sn-process nil)
  157. (set-process-filter sn-process 'sn-filter)
  158. (set-process-sentinel sn-process 'sn-sentinel)
  159. (and tmpfilename
  160. (delete-file (expand-file-name tmpfilename directory))))))
  161. ;; This quoting is sufficient to protect eg a filename from any sort
  162. ;; of expansion or splitting. Tcl quoting sure sucks.
  163. (defun sn-tcl-quote (string)
  164. (mapconcat (function (lambda (char)
  165. (if (memq char '(?[ ?] ?{ ?} ?\\ ?\" ?$ ? ?\;))
  166. (concat "\\" (char-to-string char))
  167. (char-to-string char))))
  168. string ""))
  169. ;; Send a command to SN.
  170. (defun sn-send (string)
  171. (process-send-string sn-process (concat string "\n")))
  172. ;; This is run on a hook after a file is saved. If we have to, we
  173. ;; notify the appropriate SN.
  174. (defun sn-after-save ()
  175. (if sn-minor-mode
  176. (sn-send (concat "sn_parse_uptodate " (sn-tcl-quote sn-file-name)
  177. " 0")))) ; Disable annoying popup.
  178. ;; This is the process filter for reading from SN. It just tries to
  179. ;; read the process buffer as a lisp object; when the read succeeds,
  180. ;; the result is evalled.
  181. (defun sn-filter (proc string)
  182. ;; Only do the work if the process buffer is alive.
  183. (if (buffer-name (process-buffer proc))
  184. (let ((inhibit-quit t)
  185. (sn-current-process proc)
  186. form form-list)
  187. (save-match-data
  188. (save-excursion
  189. (set-buffer (process-buffer proc))
  190. ;; If process marker not already set, we must set it.
  191. ;; This seems to contradict the docs; go figure.
  192. (or (marker-position (process-mark proc))
  193. (set-marker (process-mark proc) (point-min)))
  194. (goto-char (process-mark proc))
  195. (insert string)
  196. (set-marker (process-mark proc) (point))
  197. (goto-char (point-min))
  198. ;; Note that we only catch end-of-file. invalid-read-syntax
  199. ;; we let through; that indicates an SN bug that we really
  200. ;; want to see.
  201. (while (progn
  202. (setq form (condition-case nil
  203. (read (current-buffer))
  204. (end-of-file nil)))
  205. form)
  206. ;; Remove the stuff we've read.
  207. (delete-region (point-min) (point))
  208. (setq form-list (cons form form-list)))))
  209. ;; Now go through each form on our list and eval it. We do
  210. ;; this outside the save-excursion because we want the
  211. ;; expression to be able to move point around. We also turn
  212. ;; C-g back on.
  213. (nreverse form-list)
  214. (setq inhibit-quit nil)
  215. (while form-list
  216. (eval (car form-list))
  217. (setq form-list (cdr form-list))))))
  218. ;; This is run when the SN connection dies. We go through each buffer
  219. ;; and do some cleaning up. We also remove our own process buffer.
  220. (defun sn-sentinel (process event)
  221. (save-excursion
  222. (let ((b-list (buffer-list)))
  223. (while b-list
  224. (set-buffer (car b-list))
  225. (if (eq sn-process process)
  226. (progn
  227. ;; This buffer belongs to the current invocation. Close
  228. ;; down.
  229. (setq sn-process nil)
  230. (setq sn-minor-mode nil)))
  231. (setq b-list (cdr b-list)))))
  232. (kill-buffer (process-buffer process)))
  233. ;;;
  234. ;;; Functions that are run by SN. These functions can assume that
  235. ;;; sn-current-process is set, if they like.
  236. ;;;
  237. ;; Sent by SN when we should visit a file.
  238. ;; Arguments are:
  239. ;; * DIRECTORY - base directory of project
  240. ;; * PARTIAL-FILE - possibly-relative filename
  241. ;; * LINE, COLUMN - where cursor should end up
  242. ;; * STATE - either "normal" or "disabled"; the latter means read-only
  243. (defun sn-visit (directory partial-file line column state)
  244. (let* ((file (expand-file-name partial-file directory))
  245. (obuf (get-file-buffer file)))
  246. (cond (obuf (switch-to-buffer obuf)
  247. (push-mark))
  248. (t (set-buffer (if (string= state "disabled")
  249. (find-file-read-only file)
  250. (find-file file))))))
  251. (setq sn-process sn-current-process)
  252. (goto-line line)
  253. (forward-char column)
  254. (setq sn-minor-mode t)
  255. (setq sn-file-name partial-file)
  256. (add-hook 'after-save-hook 'sn-after-save nil t))
  257. ;; This command is sent by SN when a buffer we have should be put into
  258. ;; SN mode. It actually sends a list of (possibly relative) filenames
  259. ;; and the project's root directory.
  260. (defun sn-mark-for-project (directory file-list)
  261. (save-excursion
  262. (let (buffer
  263. file)
  264. (while file-list
  265. (setq file (expand-file-name (car file-list) directory))
  266. (setq buffer (get-file-buffer file))
  267. (if buffer
  268. (progn
  269. (set-buffer buffer)
  270. (if (not sn-minor-mode)
  271. (progn
  272. (setq sn-minor-mode t)
  273. (setq sn-process sn-current-process)))))
  274. (setq file-list (cdr file-list))))))
  275. (provide 'sn)
  276. ;;; sn.el ends here