sort.el 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. ;;; semantic/sort.el --- Utilities for sorting and re-arranging tag tables.
  2. ;;; Copyright (C) 1999-2005, 2007-2012 Free Software Foundation, Inc.
  3. ;; Author: Eric M. Ludlam <zappo@gnu.org>
  4. ;; Keywords: syntax
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;
  18. ;; Tag tables originate in the order they appear in a buffer, or source file.
  19. ;; It is often useful to re-arrange them is some predictable way for browsing
  20. ;; purposes. Re-organization may be alphabetical, or even a complete
  21. ;; reorganization of parents and children.
  22. ;;
  23. ;; Originally written in semantic/util.el
  24. ;;
  25. (require 'semantic)
  26. (eval-when-compile
  27. (require 'semantic/find))
  28. (declare-function semanticdb-find-tags-external-children-of-type
  29. "semantic/db-find")
  30. ;;; Alphanumeric sorting
  31. ;;
  32. ;; Takes a list of tags, and sorts them in a case-insensitive way
  33. ;; at a single level.
  34. ;;; Code:
  35. (defun semantic-string-lessp-ci (s1 s2)
  36. "Case insensitive version of `string-lessp'.
  37. Argument S1 and S2 are the strings to compare."
  38. ;; Use downcase instead of upcase because an average name
  39. ;; has more lower case characters.
  40. (if (fboundp 'compare-strings)
  41. (eq (compare-strings s1 0 nil s2 0 nil t) -1)
  42. (string-lessp (downcase s1) (downcase s2))))
  43. (defun semantic-sort-tag-type (tag)
  44. "Return a type string for TAG guaranteed to be a string."
  45. (let ((ty (semantic-tag-type tag)))
  46. (cond ((stringp ty)
  47. ty)
  48. ((listp ty)
  49. (or (car ty) ""))
  50. (t ""))))
  51. (defun semantic-tag-lessp-name-then-type (A B)
  52. "Return t if tag A is < tag B.
  53. First sorts on name, then sorts on the name of the :type of
  54. each tag."
  55. (let ((na (semantic-tag-name A))
  56. (nb (semantic-tag-name B))
  57. )
  58. (if (string-lessp na nb)
  59. t ; a sure thing.
  60. (if (string= na nb)
  61. ;; If equal, test the :type which might be different.
  62. (let* ((ta (semantic-tag-type A))
  63. (tb (semantic-tag-type B))
  64. (tas (cond ((stringp ta)
  65. ta)
  66. ((semantic-tag-p ta)
  67. (semantic-tag-name ta))
  68. (t nil)))
  69. (tbs (cond ((stringp tb)
  70. tb)
  71. ((semantic-tag-p tb)
  72. (semantic-tag-name tb))
  73. (t nil))))
  74. (if (and (stringp tas) (stringp tbs))
  75. (string< tas tbs)
  76. ;; This is if A == B, and no types in A or B
  77. nil))
  78. ;; This nil is if A > B, but not =
  79. nil))))
  80. (defun semantic-sort-tags-by-name-increasing (tags)
  81. "Sort TAGS by name in increasing order with side effects.
  82. Return the sorted list."
  83. (sort tags (lambda (a b)
  84. (string-lessp (semantic-tag-name a)
  85. (semantic-tag-name b)))))
  86. (defun semantic-sort-tags-by-name-decreasing (tags)
  87. "Sort TAGS by name in decreasing order with side effects.
  88. Return the sorted list."
  89. (sort tags (lambda (a b)
  90. (string-lessp (semantic-tag-name b)
  91. (semantic-tag-name a)))))
  92. (defun semantic-sort-tags-by-type-increasing (tags)
  93. "Sort TAGS by type in increasing order with side effects.
  94. Return the sorted list."
  95. (sort tags (lambda (a b)
  96. (string-lessp (semantic-sort-tag-type a)
  97. (semantic-sort-tag-type b)))))
  98. (defun semantic-sort-tags-by-type-decreasing (tags)
  99. "Sort TAGS by type in decreasing order with side effects.
  100. Return the sorted list."
  101. (sort tags (lambda (a b)
  102. (string-lessp (semantic-sort-tag-type b)
  103. (semantic-sort-tag-type a)))))
  104. (defun semantic-sort-tags-by-name-increasing-ci (tags)
  105. "Sort TAGS by name in increasing order with side effects.
  106. Return the sorted list."
  107. (sort tags (lambda (a b)
  108. (semantic-string-lessp-ci (semantic-tag-name a)
  109. (semantic-tag-name b)))))
  110. (defun semantic-sort-tags-by-name-decreasing-ci (tags)
  111. "Sort TAGS by name in decreasing order with side effects.
  112. Return the sorted list."
  113. (sort tags (lambda (a b)
  114. (semantic-string-lessp-ci (semantic-tag-name b)
  115. (semantic-tag-name a)))))
  116. (defun semantic-sort-tags-by-type-increasing-ci (tags)
  117. "Sort TAGS by type in increasing order with side effects.
  118. Return the sorted list."
  119. (sort tags (lambda (a b)
  120. (semantic-string-lessp-ci (semantic-sort-tag-type a)
  121. (semantic-sort-tag-type b)))))
  122. (defun semantic-sort-tags-by-type-decreasing-ci (tags)
  123. "Sort TAGS by type in decreasing order with side effects.
  124. Return the sorted list."
  125. (sort tags (lambda (a b)
  126. (semantic-string-lessp-ci (semantic-sort-tag-type b)
  127. (semantic-sort-tag-type a)))))
  128. (defun semantic-sort-tags-by-name-then-type-increasing (tags)
  129. "Sort TAGS by name, then type in increasing order with side effects.
  130. Return the sorted list."
  131. (sort tags (lambda (a b) (semantic-tag-lessp-name-then-type a b))))
  132. (defun semantic-sort-tags-by-name-then-type-decreasing (tags)
  133. "Sort TAGS by name, then type in increasing order with side effects.
  134. Return the sorted list."
  135. (sort tags (lambda (a b) (semantic-tag-lessp-name-then-type b a))))
  136. ;;; Unique
  137. ;;
  138. ;; Scan a list of tags, removing duplicates.
  139. ;; This must first sort the tags by name alphabetically ascending.
  140. ;;
  141. ;; Useful for completion lists, or other situations where the
  142. ;; other data isn't as useful.
  143. (defun semantic-unique-tag-table-by-name (tags)
  144. "Scan a list of TAGS, removing duplicate names.
  145. This must first sort the tags by name alphabetically ascending.
  146. For more complex uniqueness testing used by the semanticdb
  147. typecaching system, see `semanticdb-typecache-merge-streams'."
  148. (let ((sorted (semantic-sort-tags-by-name-increasing
  149. (copy-sequence tags)))
  150. (uniq nil))
  151. (while sorted
  152. (if (or (not uniq)
  153. (not (string= (semantic-tag-name (car sorted))
  154. (semantic-tag-name (car uniq)))))
  155. (setq uniq (cons (car sorted) uniq)))
  156. (setq sorted (cdr sorted))
  157. )
  158. (nreverse uniq)))
  159. (defun semantic-unique-tag-table (tags)
  160. "Scan a list of TAGS, removing duplicates.
  161. This must first sort the tags by position ascending.
  162. TAGS are removed only if they are equivalent, as can happen when
  163. multiple tag sources are scanned.
  164. For more complex uniqueness testing used by the semanticdb
  165. typecaching system, see `semanticdb-typecache-merge-streams'."
  166. (let ((sorted (sort (copy-sequence tags)
  167. (lambda (a b)
  168. (cond ((not (semantic-tag-with-position-p a))
  169. t)
  170. ((not (semantic-tag-with-position-p b))
  171. nil)
  172. (t
  173. (< (semantic-tag-start a)
  174. (semantic-tag-start b)))))))
  175. (uniq nil))
  176. (while sorted
  177. (if (or (not uniq)
  178. (not (semantic-equivalent-tag-p (car sorted) (car uniq))))
  179. (setq uniq (cons (car sorted) uniq)))
  180. (setq sorted (cdr sorted))
  181. )
  182. (nreverse uniq)))
  183. ;;; Tag Table Flattening
  184. ;;
  185. ;; In the 1.4 search API, there was a parameter "search-parts" which
  186. ;; was used to find tags inside other tags. This was used
  187. ;; infrequently, mostly for completion/jump routines. These types
  188. ;; of commands would be better off with a flattened list, where all
  189. ;; tags appear at the top level.
  190. ;;;###autoload
  191. (defun semantic-flatten-tags-table (&optional table)
  192. "Flatten the tags table TABLE.
  193. All tags in TABLE, and all components of top level tags
  194. in TABLE will appear at the top level of list.
  195. Tags promoted to the top of the list will still appear
  196. unmodified as components of their parent tags."
  197. (let* ((table (semantic-something-to-tag-table table))
  198. ;; Initialize the starting list with our table.
  199. (lists (list table)))
  200. (mapc (lambda (tag)
  201. (let ((components (semantic-tag-components tag)))
  202. (if (and components
  203. ;; unpositioned tags can be hazardous to
  204. ;; completion. Do we need any type of tag
  205. ;; here? - EL
  206. (semantic-tag-with-position-p (car components)))
  207. (setq lists (cons
  208. (semantic-flatten-tags-table components)
  209. lists)))))
  210. table)
  211. (apply 'append (nreverse lists))
  212. ))
  213. ;;; Buckets:
  214. ;;
  215. ;; A list of tags can be grouped into buckets based on the tag class.
  216. ;; Bucketize means to take a list of tags at a given level in a tag
  217. ;; table, and reorganize them into buckets based on class.
  218. ;;
  219. (defvar semantic-bucketize-tag-class
  220. ;; Must use lambda because `semantic-tag-class' is a macro.
  221. (lambda (tok) (semantic-tag-class tok))
  222. "Function used to get a symbol describing the class of a tag.
  223. This function must take one argument of a semantic tag.
  224. It should return a symbol found in `semantic-symbol->name-assoc-list'
  225. which `semantic-bucketize' uses to bin up tokens.
  226. To create new bins for an application augment
  227. `semantic-symbol->name-assoc-list', and
  228. `semantic-symbol->name-assoc-list-for-type-parts' in addition
  229. to setting this variable (locally in your function).")
  230. (defun semantic-bucketize (tags &optional parent filter)
  231. "Sort TAGS into a group of buckets based on tag class.
  232. Unknown classes are placed in a Misc bucket.
  233. Type bucket names are defined by either `semantic-symbol->name-assoc-list'.
  234. If PARENT is specified, then TAGS belong to this PARENT in some way.
  235. This will use `semantic-symbol->name-assoc-list-for-type-parts' to
  236. generate bucket names.
  237. Optional argument FILTER is a filter function to be applied to each bucket.
  238. The filter function will take one argument, which is a list of tokens, and
  239. may re-organize the list with side-effects."
  240. (let* ((name-list (if parent
  241. semantic-symbol->name-assoc-list-for-type-parts
  242. semantic-symbol->name-assoc-list))
  243. (sn name-list)
  244. (bins (make-vector (1+ (length sn)) nil))
  245. ask tagtype
  246. (nsn nil)
  247. (num 1)
  248. (out nil))
  249. ;; Build up the bucket vector
  250. (while sn
  251. (setq nsn (cons (cons (car (car sn)) num) nsn)
  252. sn (cdr sn)
  253. num (1+ num)))
  254. ;; Place into buckets
  255. (while tags
  256. (setq tagtype (funcall semantic-bucketize-tag-class (car tags))
  257. ask (assq tagtype nsn)
  258. num (or (cdr ask) 0))
  259. (aset bins num (cons (car tags) (aref bins num)))
  260. (setq tags (cdr tags)))
  261. ;; Remove from buckets into a list.
  262. (setq num 1)
  263. (while (< num (length bins))
  264. (when (aref bins num)
  265. (setq out
  266. (cons (cons
  267. (cdr (nth (1- num) name-list))
  268. ;; Filtering, First hacked by David Ponce david@dponce.com
  269. (funcall (or filter 'nreverse) (aref bins num)))
  270. out)))
  271. (setq num (1+ num)))
  272. (if (aref bins 0)
  273. (setq out (cons (cons "Misc"
  274. (funcall (or filter 'nreverse) (aref bins 0)))
  275. out)))
  276. (nreverse out)))
  277. ;;; Adoption
  278. ;;
  279. ;; Some languages allow children of a type to be defined outside
  280. ;; the syntactic scope of that class. These routines will find those
  281. ;; external members, and bring them together in a cloned copy of the
  282. ;; class tag.
  283. ;;
  284. (defvar semantic-orphaned-member-metaparent-type "class"
  285. "In `semantic-adopt-external-members', the type of 'type for metaparents.
  286. A metaparent is a made-up type semantic token used to hold the child list
  287. of orphaned members of a named type.")
  288. (make-variable-buffer-local 'semantic-orphaned-member-metaparent-type)
  289. (defvar semantic-mark-external-member-function nil
  290. "Function called when an externally defined orphan is found.
  291. By default, the token is always marked with the `adopted' property.
  292. This function should be locally bound by a program that needs
  293. to add additional behaviors into the token list.
  294. This function is called with two arguments. The first is TOKEN which is
  295. a shallow copy of the token to be modified. The second is the PARENT
  296. which is adopting TOKEN. This function should return TOKEN (or a copy of it)
  297. which is then integrated into the revised token list.")
  298. (defun semantic-adopt-external-members (tags)
  299. "Rebuild TAGS so that externally defined members are regrouped.
  300. Some languages such as C++ and CLOS permit the declaration of member
  301. functions outside the definition of the class. It is easier to study
  302. the structure of a program when such methods are grouped together
  303. more logically.
  304. This function uses `semantic-tag-external-member-p' to
  305. determine when a potential child is an externally defined member.
  306. Note: Applications which use this function must account for token
  307. types which do not have a position, but have children which *do*
  308. have positions.
  309. Applications should use `semantic-mark-external-member-function'
  310. to modify all tags which are found as externally defined to some
  311. type. For example, changing the token type for generating extra
  312. buckets with the bucket function."
  313. (let ((parent-buckets nil)
  314. (decent-list nil)
  315. (out nil)
  316. (tmp nil)
  317. )
  318. ;; Rebuild the output list, stripping out all parented
  319. ;; external entries
  320. (while tags
  321. (cond
  322. ((setq tmp (semantic-tag-external-member-parent (car tags)))
  323. (let ((tagcopy (semantic-tag-clone (car tags)))
  324. (a (assoc tmp parent-buckets)))
  325. (semantic--tag-put-property-no-side-effect tagcopy 'adopted t)
  326. (if a
  327. ;; If this parent is already in the list, append.
  328. (setcdr (nthcdr (1- (length a)) a) (list tagcopy))
  329. ;; If not, prepend this new parent bucket into our list
  330. (setq parent-buckets
  331. (cons (cons tmp (list tagcopy)) parent-buckets)))
  332. ))
  333. ((eq (semantic-tag-class (car tags)) 'type)
  334. ;; Types need to be rebuilt from scratch so we can add in new
  335. ;; children to the child list. Only the top-level cons
  336. ;; cells need to be duplicated so we can hack out the
  337. ;; child list later.
  338. (setq out (cons (semantic-tag-clone (car tags)) out))
  339. (setq decent-list (cons (car out) decent-list))
  340. )
  341. (t
  342. ;; Otherwise, append this tag to our new output list.
  343. (setq out (cons (car tags) out)))
  344. )
  345. (setq tags (cdr tags)))
  346. ;; Rescan out, by descending into all types and finding parents
  347. ;; for all entries moved into the parent-buckets.
  348. (while decent-list
  349. (let* ((bucket (assoc (semantic-tag-name (car decent-list))
  350. parent-buckets))
  351. (bucketkids (cdr bucket)))
  352. (when bucket
  353. ;; Run our secondary marking function on the children
  354. (if semantic-mark-external-member-function
  355. (setq bucketkids
  356. (mapcar (lambda (tok)
  357. (funcall semantic-mark-external-member-function
  358. tok (car decent-list)))
  359. bucketkids)))
  360. ;; We have some extra kids. Merge.
  361. (semantic-tag-put-attribute
  362. (car decent-list) :members
  363. (append (semantic-tag-type-members (car decent-list))
  364. bucketkids))
  365. ;; Nuke the bucket label so it is not found again.
  366. (setcar bucket nil))
  367. (setq decent-list
  368. (append (cdr decent-list)
  369. ;; get embedded types to scan and make copies
  370. ;; of them.
  371. (mapcar
  372. (lambda (tok) (semantic-tag-clone tok))
  373. (semantic-find-tags-by-class 'type
  374. (semantic-tag-type-members (car decent-list)))))
  375. )))
  376. ;; Scan over all remaining lost external methods, and tack them
  377. ;; onto the end.
  378. (while parent-buckets
  379. (if (car (car parent-buckets))
  380. (let* ((tmp (car parent-buckets))
  381. (fauxtag (semantic-tag-new-type
  382. (car tmp)
  383. semantic-orphaned-member-metaparent-type
  384. nil ;; Part list
  385. nil ;; parents (unknown)
  386. ))
  387. (bucketkids (cdr tmp)))
  388. (semantic-tag-set-faux fauxtag) ;; properties
  389. (if semantic-mark-external-member-function
  390. (setq bucketkids
  391. (mapcar (lambda (tok)
  392. (funcall semantic-mark-external-member-function
  393. tok fauxtag))
  394. bucketkids)))
  395. (semantic-tag-put-attribute fauxtag :members bucketkids)
  396. ;; We have a bunch of methods with no parent in this file.
  397. ;; Create a meta-type to hold it.
  398. (setq out (cons fauxtag out))
  399. ))
  400. (setq parent-buckets (cdr parent-buckets)))
  401. ;; Return the new list.
  402. (nreverse out)))
  403. ;;; External children
  404. ;;
  405. ;; In order to adopt external children, we need a few overload methods
  406. ;; to enable the feature.
  407. ;;;###autoload
  408. (define-overloadable-function semantic-tag-external-member-parent (tag)
  409. "Return a parent for TAG when TAG is an external member.
  410. TAG is an external member if it is defined at a toplevel and
  411. has some sort of label defining a parent. The parent return will
  412. be a string.
  413. The default behavior, if not overridden with
  414. `tag-member-parent' gets the 'parent extra
  415. specifier of TAG.
  416. If this function is overridden, use
  417. `semantic-tag-external-member-parent-default' to also
  418. include the default behavior, and merely extend your own."
  419. )
  420. (defun semantic-tag-external-member-parent-default (tag)
  421. "Return the name of TAGs parent only if TAG is not defined in its parent."
  422. ;; Use only the extra spec because a type has a parent which
  423. ;; means something completely different.
  424. (let ((tp (semantic-tag-get-attribute tag :parent)))
  425. (when (stringp tp)
  426. tp)))
  427. (define-overloadable-function semantic-tag-external-member-p (parent tag)
  428. "Return non-nil if PARENT is the parent of TAG.
  429. TAG is an external member of PARENT when it is somehow tagged
  430. as having PARENT as its parent.
  431. PARENT and TAG must both be semantic tags.
  432. The default behavior, if not overridden with
  433. `tag-external-member-p' is to match :parent attribute in
  434. the name of TAG.
  435. If this function is overridden, use
  436. `semantic-tag-external-member-children-p-default' to also
  437. include the default behavior, and merely extend your own."
  438. )
  439. (defun semantic-tag-external-member-p-default (parent tag)
  440. "Return non-nil if PARENT is the parent of TAG."
  441. ;; Use only the extra spec because a type has a parent which
  442. ;; means something completely different.
  443. (let ((tp (semantic-tag-external-member-parent tag)))
  444. (and (stringp tp)
  445. (string= (semantic-tag-name parent) tp))))
  446. (define-overloadable-function semantic-tag-external-member-children (tag &optional usedb)
  447. "Return the list of children which are not *in* TAG.
  448. If optional argument USEDB is non-nil, then also search files in
  449. the Semantic Database. If USEDB is a list of databases, search those
  450. databases.
  451. Children in this case are functions or types which are members of
  452. TAG, such as the parts of a type, but which are not defined inside
  453. the class. C++ and CLOS both permit methods of a class to be defined
  454. outside the bounds of the class' definition.
  455. The default behavior, if not overridden with
  456. `tag-external-member-children' is to search using
  457. `semantic-tag-external-member-p' in all top level definitions
  458. with a parent of TAG.
  459. If this function is overridden, use
  460. `semantic-tag-external-member-children-default' to also
  461. include the default behavior, and merely extend your own."
  462. )
  463. (defun semantic-tag-external-member-children-default (tag &optional usedb)
  464. "Return list of external children for TAG.
  465. Optional argument USEDB specifies if the semantic database is used.
  466. See `semantic-tag-external-member-children' for details."
  467. (if (and usedb
  468. (require 'semantic/db-mode)
  469. (semanticdb-minor-mode-p)
  470. (require 'semantic/db-find))
  471. (let ((m (semanticdb-find-tags-external-children-of-type
  472. (semantic-tag-name tag))))
  473. (if m (apply #'append (mapcar #'cdr m))))
  474. (semantic--find-tags-by-function
  475. `(lambda (tok)
  476. ;; This bit of annoying backquote forces the contents of
  477. ;; tag into the generated lambda.
  478. (semantic-tag-external-member-p ',tag tok))
  479. (current-buffer))
  480. ))
  481. (define-overloadable-function semantic-tag-external-class (tag)
  482. "Return a list of real tags that faux TAG might represent.
  483. In some languages, a method can be defined on an object which is
  484. not in the same file. In this case,
  485. `semantic-adopt-external-members' will create a faux-tag. If it
  486. is necessary to get the tag from which for faux TAG was most
  487. likely derived, then this function is needed."
  488. (unless (semantic-tag-faux-p tag)
  489. (signal 'wrong-type-argument (list tag 'semantic-tag-faux-p)))
  490. (:override)
  491. )
  492. (defun semantic-tag-external-class-default (tag)
  493. "Return a list of real tags that faux TAG might represent.
  494. See `semantic-tag-external-class' for details."
  495. (if (and (require 'semantic/db-mode)
  496. (semanticdb-minor-mode-p))
  497. (let* ((semanticdb-search-system-databases nil)
  498. (m (semanticdb-find-tags-by-class
  499. (semantic-tag-class tag)
  500. (semanticdb-find-tags-by-name (semantic-tag-name tag)))))
  501. (semanticdb-strip-find-results m 'name))
  502. ;; Presumably, if the tag is faux, it is not local.
  503. nil))
  504. (provide 'semantic/sort)
  505. ;; Local variables:
  506. ;; generated-autoload-file: "loaddefs.el"
  507. ;; generated-autoload-load-name: "semantic/sort"
  508. ;; End:
  509. ;;; semantic/sort.el ends here