commit 53cf3cfec12250d89790482d031f95a3cd5c484a (HEAD, refs/remotes/origin/master) Author: Dmitry Gutov Date: Fri Jul 10 04:38:16 2015 +0300 Don't check the exit status, it can be misleading * lisp/progmodes/xref.el (xref-collect-matches): Don't check the exit status, it can be misleading. diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 042429e..e76f0ed 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -772,12 +772,12 @@ tools are used, and when." hits) (with-current-buffer buf (erase-buffer) - (when (eq (call-process-shell-command command nil t) 0) - (goto-char (point-min)) - (while (re-search-forward grep-re nil t) - (push (cons (string-to-number (match-string 2)) - (match-string 1)) - hits)))) + (call-process-shell-command command nil t) + (goto-char (point-min)) + (while (re-search-forward grep-re nil t) + (push (cons (string-to-number (match-string 2)) + (match-string 1)) + hits))) (unwind-protect (delq nil (mapcar (lambda (hit) (xref--collect-match hit regexp)) commit f8c720b55b9419c849ea9febe6f888761a61949b Author: Dmitry Gutov Date: Fri Jul 10 04:34:41 2015 +0300 Introduce a Project API * lisp/progmodes/project.el: New file. * lisp/cedet/ede.el: (project-try-ede): New function. (project-root): New implementation. * lisp/progmodes/elisp-mode.el (emacs-lisp-mode): Set project-search-path-function. (elisp--xref-find-references): Delegate some logic to project-search-path. (elisp-search-path): New function. (elisp-xref-find): Don't implement `matches' anymore. * lisp/progmodes/etags.el: Don't implement `matches'. Delegate some logic to project-search-path. (etags-search-path): New function. * lisp/progmodes/xref.el (xref-find-function): Remove `matches' from the API. (xref-find-regexp): Move whatever common logic was in elisp and etags implementations, and search the directories returned by project-directories and project-search-path. diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el index 43660a8..9e92fc7 100644 --- a/lisp/cedet/ede.el +++ b/lisp/cedet/ede.el @@ -1517,6 +1517,22 @@ It does not apply the value to buffers." "Commit change to local variables in PROJ." nil) +;;; Integration with project.el + +(defun project-try-ede (dir) + (let ((project-dir + (locate-dominating-file + dir + (lambda (dir) + (ede-directory-get-open-project dir 'ROOT))))) + (when project-dir + (ede-directory-get-open-project project-dir 'ROOT)))) + +(cl-defmethod project-root ((project ede-project)) + (ede-project-root-directory project)) + +(add-hook 'project-find-functions #'project-try-ede) + (provide 'ede) ;; Include this last because it depends on ede. diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 335a24b..aa02b04 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -229,6 +229,7 @@ Blank lines separate paragraphs. Semicolons start comments. :group 'lisp (defvar xref-find-function) (defvar xref-identifier-completion-table-function) + (defvar project-search-path-function) (lisp-mode-variables nil nil 'elisp) (add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers) (setq-local electric-pair-text-pairs @@ -240,6 +241,7 @@ Blank lines separate paragraphs. Semicolons start comments. (setq-local xref-find-function #'elisp-xref-find) (setq-local xref-identifier-completion-table-function #'elisp--xref-identifier-completion-table) + (setq-local project-search-path-function #'elisp-search-path) (add-hook 'completion-at-point-functions #'elisp-completion-at-point nil 'local)) @@ -593,9 +595,7 @@ It can be quoted, or be inside a quoted form." (when sym (elisp--xref-find-definitions sym)))) (`references - (elisp--xref-find-matches id #'xref-collect-references)) - (`matches - (elisp--xref-find-matches id #'xref-collect-matches)) + (elisp--xref-find-references id)) (`apropos (elisp--xref-find-apropos id)))) @@ -654,29 +654,14 @@ It can be quoted, or be inside a quoted form." lst)))) lst))) -(defvar package-user-dir) - -(defun elisp--xref-find-matches (symbol fun) - (let* ((dirs (sort - (mapcar - (lambda (dir) - (file-name-as-directory (expand-file-name dir))) - ;; It's one level above a number of `load-path' - ;; elements (one for each installed package). - ;; Save us some process calls. - (cons package-user-dir load-path)) - #'string<)) - (ref dirs)) - ;; Delete subdirectories from the list. - (while (cdr ref) - (if (string-prefix-p (car ref) (cadr ref)) - (setcdr ref (cddr ref)) - (setq ref (cdr ref)))) - (cl-mapcan - (lambda (dir) - (and (file-exists-p dir) - (funcall fun symbol dir))) - dirs))) +(declare-function project-search-path "project") +(declare-function project-current "project") + +(defun elisp--xref-find-references (symbol) + (cl-mapcan + (lambda (dir) + (xref-collect-references symbol dir)) + (project-search-path (project-current)))) (defun elisp--xref-find-apropos (regexp) (apply #'nconc @@ -719,6 +704,10 @@ It can be quoted, or be inside a quoted form." (cl-defmethod xref-location-group ((l xref-elisp-location)) (xref-elisp-location-file l)) +(defun elisp-search-path () + (defvar package-user-dir) + (cons package-user-dir load-path)) + ;;; Elisp Interaction mode (defvar lisp-interaction-mode-map diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el index fc986f3..f5745a9 100644 --- a/lisp/progmodes/etags.el +++ b/lisp/progmodes/etags.el @@ -2087,18 +2087,15 @@ for \\[find-tag] (which see)." (defun etags-xref-find (action id) (pcase action (`definitions (etags--xref-find-definitions id)) - (`references - (etags--xref-find-matches id #'xref-collect-references)) - (`matches - (etags--xref-find-matches id #'xref-collect-matches)) + (`references (etags--xref-find-references id)) (`apropos (etags--xref-find-definitions id t)))) -(defun etags--xref-find-matches (input fun) - (let ((dirs (if tags-table-list - (mapcar #'file-name-directory tags-table-list) - ;; If no tags files are loaded, prompt for the dir. - (list (read-directory-name "In directory: " nil nil t))))) - (cl-mapcan (lambda (dir) (funcall fun input dir)) dirs))) +(defun etags--xref-find-references (symbol) + ;; TODO: Merge together with the Elisp impl. + (cl-mapcan + (lambda (dir) + (xref-collect-references symbol dir)) + (project-search-path (project-current)))) (defun etags--xref-find-definitions (pattern &optional regexp?) ;; This emulates the behaviour of `find-tag-in-order' but instead of @@ -2154,6 +2151,9 @@ for \\[find-tag] (which see)." (with-slots (tag-info) l (nth 1 tag-info))) +(defun etags-search-path () + (mapcar #'file-name-directory tags-table-list)) + (provide 'etags) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el new file mode 100644 index 0000000..26b32b4 --- /dev/null +++ b/lisp/progmodes/project.el @@ -0,0 +1,119 @@ +;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This file contains generic infrastructure for dealing with +;; projects, and a number of public functions: finding the current +;; root, related project directories, search path, etc. + +;;; Code: + +(require 'cl-generic) + +(defvar project-find-functions (list #'project-try-vc + #'project-ask-user) + "Special hook to find the project containing a given directory. +Each functions on this hook is called in turn with one +argument (the directory) and should return either nil to mean +that it is not applicable, or a project instance.") + +(declare-function etags-search-path "etags" ()) + +(defvar project-search-path-function #'etags-search-path + "Function that returns a list of source directories. + +The directories in which we can look for the declarations or +other references to the symbols used in the current buffer. +Depending on the language, it should include the headers search +path, load path, class path, and so on. + +The directory names should be absolute. Normally set by the +major mode. Used in the default implementation of +`project-search-path'.") + +;;;###autoload +(defun project-current (&optional dir) + "Return the project instance in DIR or `default-directory'." + (unless dir (setq dir default-directory)) + (run-hook-with-args-until-success 'project-find-functions dir)) + +(cl-defgeneric project-root (project) + "Return the root directory of the current project. +The directory name should be absolute.") + +(cl-defgeneric project-search-path (project) + "Return the list of source directories. +Including any where source (or header, etc) files used by the +current project may be found, inside or outside of the project +tree. The directory names should be absolute. + +A specialized implementation should use the value +`project-search-path-function', or, better yet, call and combine +the results from the functions that this value is set to by all +major modes used in the project. Alternatively, it can return a +user-configurable value." + (project--prune-directories + (nconc (funcall project-search-path-function) + ;; Include these, because we don't know any better. + ;; But a specialized implementation may include only some of + ;; the project's subdirectories, if there are no source + ;; files at the top level. + (project-directories project)))) + +(cl-defgeneric project-directories (project) + "Return the list of directories related to the current project. +It should include the current project root, as well as the roots +of any currently open related projects, if they're meant to be +edited together. The directory names should be absolute." + (list (project-root project))) + +(defun project-try-vc (dir) + (let* ((backend (ignore-errors (vc-responsible-backend dir))) + (root (and backend (ignore-errors + (vc-call-backend backend 'root dir))))) + (and root (cons 'vc root)))) + +(cl-defmethod project-root ((project (head vc))) + (cdr project)) + +(defun project-ask-user (dir) + (cons 'user (read-directory-name "Project root: " dir nil t))) + +(cl-defmethod project-root ((project (head user))) + (cdr project)) + +(defun project--prune-directories (dirs) + "Returns a copy of DIRS sorted, without subdirectories or non-existing ones." + (let* ((dirs (sort + (mapcar + (lambda (dir) + (file-name-as-directory (expand-file-name dir))) + dirs) + #'string<)) + (ref dirs)) + ;; Delete subdirectories from the list. + (while (cdr ref) + (if (string-prefix-p (car ref) (cadr ref)) + (setcdr ref (cddr ref)) + (setq ref (cdr ref)))) + (cl-delete-if-not #'file-exists-p dirs))) + +(provide 'project) +;;; project.el ends here diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index f175c89..042429e 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -54,6 +54,7 @@ (require 'eieio) (require 'ring) (require 'pcase) +(require 'project) (defgroup xref nil "Cross-referencing commands" :group 'tools) @@ -182,9 +183,6 @@ found, return nil. (apropos PATTERN): Find all symbols that match PATTERN. PATTERN is a regexp. - (matches REGEXP): Find all matches for REGEXP in the related -files. REGEXP is an Emacs regular expression. - IDENTIFIER can be any string returned by `xref-identifier-at-point-function', or from the table returned by `xref-identifier-completion-table-function'. @@ -598,7 +596,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)." (tb (cl-set-difference (buffer-list) bl))) (cond ((null xrefs) - (user-error "No known %s for: %s" (symbol-name kind) input)) + (user-error "No %s found for: %s" (symbol-name kind) input)) ((not (cdr xrefs)) (xref-push-marker-stack) (xref--pop-to-location (xref--xref-location (car xrefs)) window)) @@ -661,10 +659,25 @@ With prefix argument, prompt for the identifier." ;;;###autoload (defun xref-find-regexp (regexp) - "Find all matches for REGEXP." + "Find all matches for REGEXP. +With \\[universal-argument] prefix, you can specify the directory +to search in." ;; FIXME: Prompt for directory. (interactive (list (xref--read-identifier "Find regexp: "))) - (xref--show-xrefs regexp 'matches regexp nil)) + (let* ((dirs (if current-prefix-arg + (list (read-directory-name "In directory: ")) + (let ((proj (project-current))) + (project--prune-directories + (nconc + (project-directories proj) + (project-search-path proj)))))) + (xref-find-function + (lambda (_kind regexp) + (cl-mapcan + (lambda (dir) + (xref-collect-matches regexp dir)) + dirs)))) + (xref--show-xrefs regexp 'matches regexp nil))) (declare-function apropos-parse-pattern "apropos" (pattern)) @@ -807,7 +820,6 @@ tools are used, and when." (xref-make-file-location file line (current-column)))))))) - (provide 'xref) ;;; xref.el ends here commit 78c3e14aafb6125ea584c78e13df41a35f18c51e Author: Nicolas Petton Date: Thu Jul 9 19:49:24 2015 +0200 * test/automated/map-tests.el (test-map-delete-return-value): Uncomment test. diff --git a/test/automated/map-tests.el b/test/automated/map-tests.el index 2bce643..1f3a07e 100644 --- a/test/automated/map-tests.el +++ b/test/automated/map-tests.el @@ -103,22 +103,22 @@ Evaluate BODY for each created map. (let ((ht (make-hash-table))) (should (eq (map-delete ht 'a) ht)))) -;; (ert-deftest test-map-nested-elt () -;; (let ((vec [a b [c d [e f]]])) -;; (should (eq (map-nested-elt vec '(2 2 0)) 'e))) -;; (let ((alist '((a . 1) -;; (b . ((c . 2) -;; (d . 3) -;; (e . ((f . 4) -;; (g . 5)))))))) -;; (should (eq (map-nested-elt alist '(b e f)) -;; 4))) -;; (let ((ht (make-hash-table))) -;; (setf (map-elt ht 'a) 1) -;; (setf (map-elt ht 'b) (make-hash-table)) -;; (setf (map-elt (map-elt ht 'b) 'c) 2) -;; (should (eq (map-nested-elt ht '(b c)) -;; 2)))) +(ert-deftest test-map-nested-elt () + (let ((vec [a b [c d [e f]]])) + (should (eq (map-nested-elt vec '(2 2 0)) 'e))) + (let ((alist '((a . 1) + (b . ((c . 2) + (d . 3) + (e . ((f . 4) + (g . 5)))))))) + (should (eq (map-nested-elt alist '(b e f)) + 4))) + (let ((ht (make-hash-table))) + (setf (map-elt ht 'a) 1) + (setf (map-elt ht 'b) (make-hash-table)) + (setf (map-elt (map-elt ht 'b) 'c) 2) + (should (eq (map-nested-elt ht '(b c)) + 2)))) (ert-deftest test-map-nested-elt-default () (let ((vec [a b [c d]])) commit 5509e2f93e790e6bf484160753493e42af04530b Author: Nicolas Petton Date: Thu Jul 9 19:43:41 2015 +0200 Add support for gv.el in map.el * lisp/emacs-lisp/map.el (map-elt, map-delete): Declare a gv-expander. * lisp/emacs-lisp/map.el (map-put): Refactor using `setf' and `map-elt'. * test/automated/map-tests.el: Update tests to work with the new implementations of map-elt and map-put. diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el index 1d8a312..5014571 100644 --- a/lisp/emacs-lisp/map.el +++ b/lisp/emacs-lisp/map.el @@ -71,36 +71,21 @@ MAP can be a list, hash-table or array." `(pcase-let ((,(map--make-pcase-patterns keys) ,map)) ,@body)) -(defmacro map--dispatch (spec &rest args) - "Evaluate one of the forms specified by ARGS based on the type of MAP. - -SPEC can be a map or a list of the form (VAR MAP [RESULT]). -ARGS should have the form [TYPE FORM]... +(eval-when-compile + (defmacro map--dispatch (map-var &rest args) + "Evaluate one of the forms specified by ARGS based on the type of MAP. The following keyword types are meaningful: `:list', `:hash-table' and `:array'. An error is thrown if MAP is neither a list, hash-table nor array. -Return RESULT if non-nil or the result of evaluation of the -form. - -\(fn (VAR MAP [RESULT]) &rest ARGS)" - (declare (debug t) (indent 1)) - (unless (listp spec) - (setq spec `(,spec ,spec))) - (let ((map-var (car spec)) - (result-var (make-symbol "result"))) - `(let ((,map-var ,(cadr spec)) - ,result-var) - (setq ,result-var - (cond ((listp ,map-var) ,(plist-get args :list)) - ((hash-table-p ,map-var) ,(plist-get args :hash-table)) - ((arrayp ,map-var) ,(plist-get args :array)) - (t (error "Unsupported map: %s" ,map-var)))) - ,@(when (cddr spec) - `((setq ,result-var ,@(cddr spec)))) - ,result-var))) +Return RESULT if non-nil or the result of evaluation of the form." + (declare (debug t) (indent 1)) + `(cond ((listp ,map-var) ,(plist-get args :list)) + ((hash-table-p ,map-var) ,(plist-get args :hash-table)) + ((arrayp ,map-var) ,(plist-get args :array)) + (t (error "Unsupported map: %s" ,map-var))))) (defun map-elt (map key &optional default) "Perform a lookup in MAP of KEY and return its associated value. @@ -109,10 +94,28 @@ If KEY is not found, return DEFAULT which defaults to nil. If MAP is a list, `eql' is used to lookup KEY. MAP can be a list, hash-table or array." + (declare + (gv-expander + (lambda (do) + (gv-letplace (mgetter msetter) `(gv-delay-error ,map) + (macroexp-let2* nil + ;; Eval them once and for all in the right order. + ((key key) (default default)) + `(if (listp ,mgetter) + ;; Special case the alist case, since it can't be handled by the + ;; map--put function. + ,(gv-get `(alist-get ,key (gv-synthetic-place + ,mgetter ,msetter) + ,default) + do) + ,(funcall do `(map-elt ,mgetter ,key ,default) + (lambda (v) `(map--put ,mgetter ,key ,v))))))))) (map--dispatch map :list (alist-get key map default) :hash-table (gethash key map default) - :array (map--elt-array map key default))) + :array (if (and (>= key 0) (< key (seq-length map))) + (seq-elt map key) + default))) (defmacro map-put (map key value) "In MAP, associate KEY with VALUE and return MAP. @@ -120,15 +123,10 @@ If KEY is already present in MAP, replace the associated value with VALUE. MAP can be a list, hash-table or array." - (declare (debug t)) - (let ((symbol (symbolp map))) + (macroexp-let2 nil map map `(progn - (map--dispatch (m ,map m) - :list (if ,symbol - (setq ,map (cons (cons ,key ,value) m)) - (error "Literal lists are not allowed, %s must be a symbol" ',map)) - :hash-table (puthash ,key ,value m) - :array (aset m ,key ,value))))) + (setf (map-elt ,map ,key) ,value) + ,map))) (defmacro map-delete (map key) "In MAP, delete the key KEY if present and return MAP. @@ -136,14 +134,16 @@ If MAP is an array, store nil at the index KEY. MAP can be a list, hash-table or array." (declare (debug t)) - (let ((symbol (symbolp map))) - `(progn - (map--dispatch (m ,map m) - :list (if ,symbol - (setq ,map (map--delete-alist m ,key)) - (error "Literal lists are not allowed, %s must be a symbol" ',map)) - :hash-table (remhash ,key m) - :array (map--delete-array m ,key))))) + (gv-letplace (mgetter msetter) `(gv-delay-error ,map) + (macroexp-let2 nil key key + `(if (not (listp ,mgetter)) + (map--delete ,mgetter ,key) + ;; The alist case is special, since it can't be handled by the + ;; map--delete function. + (setf (alist-get ,key (gv-synthetic-place ,mgetter ,msetter) + nil t) + nil) + ,mgetter)))) (defun map-nested-elt (map keys &optional default) "Traverse MAP using KEYS and return the looked up value or DEFAULT if nil. @@ -285,7 +285,7 @@ MAP can be a list, hash-table or array." (let (result) (while maps (map-apply (lambda (key value) - (map-put result key value)) + (setf (map-elt result key) value)) (pop maps))) (map-into result type))) @@ -299,6 +299,14 @@ MAP can be a list, hash-table or array." (`hash-table (map--into-hash-table map)) (_ (error "Not a map type name: %S" type)))) +(defun map--put (map key v) + (map--dispatch map + :list (let ((p (assoc key map))) + (if p (setcdr p v) + (error "No place to change the mapping for %S" key))) + :hash-table (puthash key v map) + :array (aset map key v))) + (defun map--apply-alist (function map) "Private function used to apply FUNCTION over MAP, MAP being an alist." (seq-map (lambda (pair) @@ -307,6 +315,15 @@ MAP can be a list, hash-table or array." (cdr pair))) map)) +(defun map--delete (map key) + (map--dispatch map + :list (error "No place to remove the mapping for %S" key) + :hash-table (remhash key map) + :array (and (>= key 0) + (<= key (seq-length map)) + (aset map key nil))) + map) + (defun map--apply-hash-table (function map) "Private function used to apply FUNCTION over MAP, MAP being a hash-table." (let (result) @@ -324,35 +341,12 @@ MAP can be a list, hash-table or array." (setq index (1+ index)))) map))) -(defun map--elt-array (map key &optional default) - "Return the element of the array MAP at the index KEY. -If KEY is not found, return DEFAULT which defaults to nil." - (let ((len (seq-length map))) - (or (and (>= key 0) - (<= key len) - (seq-elt map key)) - default))) - -(defun map--delete-alist (map key) - "Return MAP with KEY removed." - (seq-remove (lambda (pair) - (equal key (car pair))) - map)) - -(defun map--delete-array (map key) - "Set nil in the array MAP at the index KEY if present and return MAP." - (let ((len (seq-length map))) - (and (>= key 0) - (<= key len) - (aset map key nil))) - map) - (defun map--into-hash-table (map) "Convert MAP into a hash-table." (let ((ht (make-hash-table :size (map-length map) :test 'equal))) (map-apply (lambda (key value) - (map-put ht key value)) + (setf (map-elt ht key) value)) map) ht)) diff --git a/test/automated/map-tests.el b/test/automated/map-tests.el index abda03d..2bce643 100644 --- a/test/automated/map-tests.el +++ b/test/automated/map-tests.el @@ -1,4 +1,4 @@ -;;; map-tests.el --- Tests for map.el +;;; map-tests.el --- Tests for map.el -*- lexical-binding:t -*- ;; Copyright (C) 2015 Free Software Foundation, Inc. @@ -40,17 +40,14 @@ Evaluate BODY for each created map. (let ((alist (make-symbol "alist")) (vec (make-symbol "vec")) (ht (make-symbol "ht"))) - `(let ((,alist '((0 . 3) - (1 . 4) - (2 . 5))) - (,vec (make-vector 3 nil)) + `(let ((,alist (list (cons 0 3) + (cons 1 4) + (cons 2 5))) + (,vec (vector 3 4 5)) (,ht (make-hash-table))) - (aset ,vec 0 '3) - (aset ,vec 1 '4) - (aset ,vec 2 '5) - (puthash '0 3 ,ht) - (puthash '1 4 ,ht) - (puthash '2 5 ,ht) + (puthash 0 3 ,ht) + (puthash 1 4 ,ht) + (puthash 2 5 ,ht) (dolist (,var (list ,alist ,vec ,ht)) ,@body)))) @@ -74,26 +71,21 @@ Evaluate BODY for each created map. (ert-deftest test-map-put () (with-maps-do map + (setf (map-elt map 2) 'hello) + (should (eq (map-elt map 2) 'hello))) + (with-maps-do map (map-put map 2 'hello) (should (eq (map-elt map 2) 'hello))) (let ((ht (make-hash-table))) - (map-put ht 2 'a) + (setf (map-elt ht 2) 'a) (should (eq (map-elt ht 2) 'a))) (let ((alist '((0 . a) (1 . b) (2 . c)))) - (map-put alist 2 'a) + (setf (map-elt alist 2) 'a) (should (eq (map-elt alist 2) 'a))) (let ((vec [3 4 5])) - (should-error (map-put vec 3 6)))) - -(ert-deftest test-map-put-literal () - (should (= (map-elt (map-put [1 2 3] 1 4) 1) - 4)) - (should (= (map-elt (map-put (make-hash-table) 'a 2) 'a) - 2)) - (should-error (map-put '((a . 1)) 'b 2)) - (should-error (map-put '() 'a 1))) + (should-error (setf (map-elt vec 3) 6)))) (ert-deftest test-map-put-return-value () (let ((ht (make-hash-table))) @@ -111,22 +103,22 @@ Evaluate BODY for each created map. (let ((ht (make-hash-table))) (should (eq (map-delete ht 'a) ht)))) -(ert-deftest test-map-nested-elt () - (let ((vec [a b [c d [e f]]])) - (should (eq (map-nested-elt vec '(2 2 0)) 'e))) - (let ((alist '((a . 1) - (b . ((c . 2) - (d . 3) - (e . ((f . 4) - (g . 5)))))))) - (should (eq (map-nested-elt alist '(b e f)) - 4))) - (let ((ht (make-hash-table))) - (map-put ht 'a 1) - (map-put ht 'b (make-hash-table)) - (map-put (map-elt ht 'b) 'c 2) - (should (eq (map-nested-elt ht '(b c)) - 2)))) +;; (ert-deftest test-map-nested-elt () +;; (let ((vec [a b [c d [e f]]])) +;; (should (eq (map-nested-elt vec '(2 2 0)) 'e))) +;; (let ((alist '((a . 1) +;; (b . ((c . 2) +;; (d . 3) +;; (e . ((f . 4) +;; (g . 5)))))))) +;; (should (eq (map-nested-elt alist '(b e f)) +;; 4))) +;; (let ((ht (make-hash-table))) +;; (setf (map-elt ht 'a) 1) +;; (setf (map-elt ht 'b) (make-hash-table)) +;; (setf (map-elt (map-elt ht 'b) 'c) 2) +;; (should (eq (map-nested-elt ht '(b c)) +;; 2)))) (ert-deftest test-map-nested-elt-default () (let ((vec [a b [c d]])) @@ -215,39 +207,39 @@ Evaluate BODY for each created map. (ert-deftest test-map-filter () (with-maps-do map - (should (equal (map-keys (map-filter (lambda (k v) + (should (equal (map-keys (map-filter (lambda (_k v) (<= 4 v)) map)) '(1 2))) - (should (null (map-filter (lambda (k v) + (should (null (map-filter (lambda (k _v) (eq 'd k)) map)))) - (should (null (map-filter (lambda (k v) + (should (null (map-filter (lambda (_k v) (eq 3 v)) [1 2 4 5]))) - (should (equal (map-filter (lambda (k v) + (should (equal (map-filter (lambda (k _v) (eq 3 k)) [1 2 4 5]) '((3 . 5))))) (ert-deftest test-map-remove () (with-maps-do map - (should (equal (map-keys (map-remove (lambda (k v) + (should (equal (map-keys (map-remove (lambda (_k v) (>= v 4)) map)) '(0))) - (should (equal (map-keys (map-remove (lambda (k v) + (should (equal (map-keys (map-remove (lambda (k _v) (eq 'd k)) map)) (map-keys map)))) - (should (equal (map-remove (lambda (k v) + (should (equal (map-remove (lambda (_k v) (eq 3 v)) [1 2 4 5]) '((0 . 1) (1 . 2) (2 . 4) (3 . 5)))) - (should (null (map-remove (lambda (k v) + (should (null (map-remove (lambda (k _v) (>= k 0)) [1 2 4 5])))) @@ -270,35 +262,35 @@ Evaluate BODY for each created map. (ert-deftest test-map-some-p () (with-maps-do map - (should (equal (map-some-p (lambda (k v) + (should (equal (map-some-p (lambda (k _v) (eq 1 k)) map) (cons 1 4))) - (should (not (map-some-p (lambda (k v) + (should (not (map-some-p (lambda (k _v) (eq 'd k)) map)))) (let ((vec [a b c])) - (should (equal (map-some-p (lambda (k v) + (should (equal (map-some-p (lambda (k _v) (> k 1)) vec) (cons 2 'c))) - (should (not (map-some-p (lambda (k v) + (should (not (map-some-p (lambda (k _v) (> k 3)) vec))))) (ert-deftest test-map-every-p () (with-maps-do map - (should (map-every-p (lambda (k v) + (should (map-every-p (lambda (k _v) k) map)) - (should (not (map-every-p (lambda (k v) + (should (not (map-every-p (lambda (_k _v) nil) map)))) (let ((vec [a b c])) - (should (map-every-p (lambda (k v) + (should (map-every-p (lambda (k _v) (>= k 0)) vec)) - (should (not (map-every-p (lambda (k v) + (should (not (map-every-p (lambda (k _v) (> k 3)) vec))))) @@ -324,7 +316,8 @@ Evaluate BODY for each created map. (should (null baz))) (map-let (('foo a) ('bar b) - ('baz c)) '((foo . 1) (bar . 2)) + ('baz c)) + '((foo . 1) (bar . 2)) (should (= a 1)) (should (= b 2)) (should (null c)))) commit 2a1591f4d431777c7956146aff6d9d1602420d9e Author: Glenn Morris Date: Thu Jul 9 13:18:57 2015 -0400 * lisp/emacs-lisp/debug.el (debug-help-follow): Use describe-symbol. diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el index 77d6332..0e307fa 100644 --- a/lisp/emacs-lisp/debug.el +++ b/lisp/emacs-lisp/debug.el @@ -731,15 +731,11 @@ Complete list of commands: (buffer-substring (line-beginning-position 0) (line-end-position 0))))) -(declare-function help-xref-interned "help-mode" - (symbol &optional buffer frame)) - (defun debug-help-follow (&optional pos) "Follow cross-reference at POS, defaulting to point. For the cross-reference format, see `help-make-xrefs'." (interactive "d") - (require 'help-mode) ;; Ideally we'd just do (call-interactively 'help-follow) except that this ;; assumes we're already in a *Help* buffer and reuses it, so it ends up ;; incorrectly "reusing" the *Backtrace* buffer to show the help info. @@ -755,7 +751,7 @@ For the cross-reference format, see `help-make-xrefs'." (progn (skip-syntax-forward "w_") (point))))))) (when (or (boundp sym) (fboundp sym) (facep sym)) - (help-xref-interned sym))))) + (describe-symbol sym))))) ;; When you change this, you may also need to change the number of ;; frames that the debugger skips. commit c7e9792565dc8a8a91bb8d1e1a9f698c751a9c1e Author: Dmitry Gutov Date: Thu Jul 9 15:28:04 2015 +0300 Syntax-propertize until the end of the line first * lisp/progmodes/xref.el (xref--collect-match): Syntax-propertize until the end of the line first. diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 78094ab..f175c89 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -798,6 +798,7 @@ tools are used, and when." (save-excursion (goto-char (point-min)) (forward-line (1- line)) + (syntax-propertize (line-end-position)) (when (re-search-forward regexp (line-end-position) t) (goto-char (match-beginning 0)) (xref-make (buffer-substring commit 20368cc0120cae589bb70fc313a5ba54117d04b1 Author: Xue Fuqiao Date: Thu Jul 9 20:24:53 2015 +0800 ; Improve documentation of image-goto-frame diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index c89d3f2..6ff59b4 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -1988,8 +1988,8 @@ non-@code{nil}. With @kbd{f} (@code{image-next-frame}) and @kbd{b} (@code{image-previous-frame}) you can step through the individual frames. Both commands accept a numeric prefix to step through several frames at once. You can go to a specific frame with @kbd{F} -(@code{image-goto-frame}). Typing @kbd{a +} -(@code{image-increase-speed}) increases the speed of the animation, +(@code{image-goto-frame}). Frames are indexed from 1. Typing @kbd{a ++} (@code{image-increase-speed}) increases the speed of the animation, @kbd{a -} (@code{image-decrease-speed}) decreases it, and @kbd{a r} (@code{image-reverse-speed}) reverses it. The command @kbd{a 0} (@code{image-reset-speed}) resets the speed to the original value. commit 66c79b2d8f526ae38deeccb28a98a6bd0e31d454 Author: Xue Fuqiao Date: Thu Jul 9 19:40:41 2015 +0800 * doc/emacs/files.texi (File Archives): Add a cross reference. diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index e5c5e1b..c89d3f2 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -1745,7 +1745,8 @@ owner, are supported only for some of the archive formats. and repack archives. However, you don't need these programs to look at the archive table of contents, only to extract or manipulate the subfiles in the archive. Details of the program names and their -options can be set in the @samp{Archive} Customize group. +options can be set in the @samp{Archive} Customize group +(@pxref{Customization Groups}). @node Remote Files @section Remote Files @@ -1945,6 +1946,7 @@ opened files. @kbd{M-x recentf-save-list} saves the current @code{recent-file-list} to a file, and @kbd{M-x recentf-edit-list} edits it. +@c FIXME partial-completion-mode (complete.el) is obsolete. The @kbd{M-x ffap} command generalizes @code{find-file} with more powerful heuristic defaults (@pxref{FFAP}), often based on the text at point. Partial Completion mode offers other features extending diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi index b3ff051..5129c1c 100644 --- a/doc/emacs/help.texi +++ b/doc/emacs/help.texi @@ -360,10 +360,10 @@ view, describe, default. @vindex apropos-do-all If the variable @code{apropos-do-all} is non-@code{nil}, most -apropos commands behave as if they had been given a prefix -argument. There is one exception: @code{apropos-variable} without a -prefix argument will always search for all variables, no matter what -the value of @code{apropos-do-all} is. +apropos commands behave as if they had been given a prefix argument. +There is one exception: @code{apropos-variable} without a prefix +argument will always search for all variables, no matter what the +value of @code{apropos-do-all} is. @vindex apropos-sort-by-scores @cindex apropos search results, order by score