branch: master
commit b3034e07ecac291b2d368c4a9ba115986dd4797c
Author: Stephen Leake <stephen_le...@stephe-leake.org>
Commit: Stephen Leake <stephen_le...@stephe-leake.org>

    In uniquify-files, rewrite to use an alist, clean up tests to match
    
    * packages/uniquify-files/file-complete-root-relative-test.el: Delete.
    * packages/uniquify-files/file-complete-root-relative.el: Delete.
    * packages/uniquify-files/file-complete.el: Delete.
    
    * packages/uniquify-files/uniquify-files-resources/
    wisitoken-generate-packrat-test.text: New file.
    
    * packages/uniquify-files/uniquify-files-resources/
    wisitoken-syntax_trees-test.text: New file.
    
    * packages/uniquify-files/uniquify-files-resources/
    wisitoken-text_io_trace.text: New file.
    
    * packages/uniquify-files/uniquify-files-test.el (uft-path): Delete
    dependence on path-iterator. Simplify tests to work with rewritten
    uniquify-files.
    
    * packages/uniquify-files/uniquify-files.el: Rewrite to use alist of abs
    . uniquified.
    (uniq-file-read): New for Emacs 27 project.el.
---
 .../file-complete-root-relative-test.el            | 271 ---------
 .../uniquify-files/file-complete-root-relative.el  | 324 ----------
 packages/uniquify-files/file-complete.el           | 192 ------
 .../wisitoken-generate-packrat-test.text           |   1 +
 .../wisitoken-syntax_trees-test.text               |   1 +
 .../wisitoken-text_io_trace.text                   |   1 +
 packages/uniquify-files/uniquify-files-test.el     | 672 ++++++++-------------
 packages/uniquify-files/uniquify-files.el          | 598 ++++--------------
 8 files changed, 350 insertions(+), 1710 deletions(-)

diff --git a/packages/uniquify-files/file-complete-root-relative-test.el 
b/packages/uniquify-files/file-complete-root-relative-test.el
deleted file mode 100644
index 8b44d92..0000000
--- a/packages/uniquify-files/file-complete-root-relative-test.el
+++ /dev/null
@@ -1,271 +0,0 @@
-;;; file-complete-root-relative-test.el - Test for 
file-complete-root-relative.el -*- lexical-binding:t no-byte-compile:t -*-
-;;
-;; Copyright (C) 2017, 2019  Free Software Foundation, Inc.
-;;
-;; Author: Stephen Leake <stephen_le...@stephe-leake.org>
-;; Maintainer: Stephen Leake <stephen_le...@stephe-leake.org>
-;;
-;; 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 <http://www.gnu.org/licenses/>.
-
-(require 'ert)
-(require 'uniquify-files-test) ;; We share the test directory tree.
-(require 'file-complete-root-relative)
-
-(defconst fc-root-rel-iter (make-path-iterator :user-path-recursive (list 
uft-root)))
-
-(defconst fc-root-rel-file-list
-  (list
-    (concat uft-root "/foo-file1.text")
-    (concat uft-root "/foo-file3.texts2")
-    (concat uft-root "/Alice/alice-1/bar-file1.text")
-    (concat uft-root "/Alice/alice-1/bar-file2.text")
-    (concat uft-root "/Alice/alice-1/foo-file1.text")
-    (concat uft-root "/Alice/alice-1/foo-file2.text")
-    (concat uft-root "/Alice/alice-2/bar-file1.text")
-    (concat uft-root "/Alice/alice-2/bar-file2.text")
-    (concat uft-root "/Alice/alice-2/foo-file1.text")
-    (concat uft-root "/Alice/alice-2/foo-file3.text")
-    (concat uft-root "/Alice/alice-2/foo-file3.texts")
-    (concat uft-root "/Alice/alice-3/foo-file4.text")
-    (concat uft-root "/Bob/alice-3/foo-file4.text")
-    (concat uft-root "/Bob/bob-1/foo-file1.text")
-    (concat uft-root "/Bob/bob-1/foo-file2.text")
-    (concat uft-root "/Bob/bob-2/foo-file1.text")
-    (concat uft-root "/Bob/bob-2/foo-file5.text")
-    ))
-
-(ert-deftest test-fc-root-rel-completion-table-iter ()
-  "Test added functions of table."
-  (should (equal (fc-root-rel-completion-table-iter fc-root-rel-iter "fi" nil 
'metadata)
-                (cons 'metadata
-                      (list
-                       '(category . project-file)
-                       '(styles   . (file-root-rel))
-                       (cons 'root (file-name-as-directory uft-root))))))
-  )
-
-(ert-deftest test-fc-root-rel-completion-table-list ()
-  "Test basic functions of table."
-  ;; grouped by action
-  (should (equal (fc-root-rel-completion-table-list fc-root-rel-file-list 
uft-root "fi" nil '(boundaries . ".text"))
-                  '(boundaries . (0 . 5))))
-
-  (should (equal (fc-root-rel-completion-table-list fc-root-rel-file-list 
uft-root "fi" nil 'metadata)
-                (cons 'metadata
-                      (list
-                       '(category . project-file)
-                       '(styles   . (file-root-rel))
-                       (cons 'root uft-root)))))
-
-  ;; all-completions. We sort the results here to make the test stable
-  (should (equal (sort (fc-root-rel-completion-table-list 
fc-root-rel-file-list uft-root "" nil t) #'string-lessp)
-                (list
-                 (concat uft-alice1 "/bar-file1.text")
-                 (concat uft-alice1 "/bar-file2.text")
-                 (concat uft-alice1 "/foo-file1.text")
-                 (concat uft-alice1 "/foo-file2.text")
-                 (concat uft-alice2 "/bar-file1.text")
-                 (concat uft-alice2 "/bar-file2.text")
-                 (concat uft-alice2 "/foo-file1.text")
-                 (concat uft-alice2 "/foo-file3.text")
-                 (concat uft-alice2 "/foo-file3.texts")
-                 (concat uft-Alice-alice3 "/foo-file4.text")
-                 (concat uft-Bob-alice3 "/foo-file4.text")
-                 (concat uft-bob1 "/foo-file1.text")
-                 (concat uft-bob1 "/foo-file2.text")
-                 (concat uft-bob2 "/foo-file1.text")
-                 (concat uft-bob2 "/foo-file5.text")
-                 (concat uft-root "/foo-file1.text")
-                 (concat uft-root "/foo-file3.texts2")
-                 )))
-
-  (should (equal (sort (fc-root-rel-completion-table-list
-                       fc-root-rel-file-list uft-root "a-1/f-fi" nil t)
-                      #'string-lessp)
-                (list
-                 (concat uft-alice1 "/foo-file1.text")
-                 (concat uft-alice1 "/foo-file2.text")
-                 )))
-
-  (should (equal (fc-root-rel-completion-table-list fc-root-rel-file-list 
uft-root "uft-alice1/file1.text" nil t)
-                ;; misspelled; no match
-                nil))
-
-  ;; This table does not implement try-completion
-  (should (equal (fc-root-rel-completion-table-list fc-root-rel-file-list 
uft-root "fi" nil nil)
-                nil))
-
-  ;; test-completion
-  (should (equal (fc-root-rel-completion-table-list
-                 fc-root-rel-file-list uft-root
-                 (fc-root-rel-to-table-input "alice-1/foo-file1.text") nil 
'lambda)
-                nil)) ;; not at root
-
-  (should (equal (fc-root-rel-completion-table-iter
-                 fc-root-rel-iter
-                 (fc-root-rel-to-table-input "Alice/alice-1/foo-file1.text") 
nil 'lambda)
-                t)) ;; at root
-  )
-
-(defun test-fc-root-rel-test-completion-1 (table)
-  ;; In normal operation, 'all-completions' is called before
-  ;; test-completion, and it sets completion-current-style.
-  (let ((completion-current-style 'file-root-rel))
-    (should (equal (test-completion "foo-fi" table)
-                  nil))
-
-    (should (equal (test-completion "dir/f-fi" table)
-                  nil))
-
-    (should (equal (test-completion "foo-file1.text" table)
-                  t)) ;; starts at root
-
-    (should (equal (test-completion "alice-1/foo-file1.text" table)
-                  nil)) ;; does not start at root
-
-    (should (equal (test-completion "Alice/alice-1/foo-file1.text" table)
-                  t)) ;; starts at root
-
-    (should (equal (test-completion "foo-file3.text" table)
-                  nil))
-
-    (should (equal (test-completion "foo-file3.texts2" table)
-                  t))
-
-    (should (equal (test-completion "Alice/alice-/bar-file2.text" table)
-                  nil))
-
-    (should (equal (test-completion "Alice/alice-1/bar-file2.text" table)
-                  t))
-    ))
-
-(ert-deftest test-fc-root-rel-test-completion-iter ()
-  (let ((table (apply-partially 'fc-root-rel-completion-table-iter 
fc-root-rel-iter))
-       (completion-category-overrides '(project-file (styles . 
file-root-rel))))
-    (test-fc-root-rel-test-completion-1 table)))
-
-(ert-deftest test-fc-root-rel-test-completion-list ()
-  (let ((table (apply-partially 'fc-root-rel-completion-table-list 
fc-root-rel-file-list uft-root))
-       (completion-category-overrides '(project-file (styles . 
file-root-rel))))
-    (test-fc-root-rel-test-completion-1 table)))
-
-(defun test-fc-root-rel-all-completions-noface-1 (table)
-  (should (equal
-          (sort (fc-root-rel-all-completions "" table nil nil) #'string-lessp)
-          (list
-           "Alice/alice-1/bar-file1.text"
-           "Alice/alice-1/bar-file2.text"
-           "Alice/alice-1/foo-file1.text"
-           "Alice/alice-1/foo-file2.text"
-           "Alice/alice-2/bar-file1.text"
-           "Alice/alice-2/bar-file2.text"
-           "Alice/alice-2/foo-file1.text"
-           "Alice/alice-2/foo-file3.text"
-           "Alice/alice-2/foo-file3.texts"
-           "Alice/alice-3/foo-file4.text"
-           "Bob/alice-3/foo-file4.text"
-           "Bob/bob-1/foo-file1.text"
-           "Bob/bob-1/foo-file2.text"
-           "Bob/bob-2/foo-file1.text"
-           "Bob/bob-2/foo-file5.text"
-           "foo-file1.text"
-           "foo-file3.texts2"
-           )))
-
-  (should (equal
-          (sort (fc-root-rel-all-completions "*-fi" table nil nil) 
#'string-lessp)
-          (list
-           "Alice/alice-1/bar-file1.text"
-           "Alice/alice-1/bar-file2.text"
-           "Alice/alice-1/foo-file1.text"
-           "Alice/alice-1/foo-file2.text"
-           "Alice/alice-2/bar-file1.text"
-           "Alice/alice-2/bar-file2.text"
-           "Alice/alice-2/foo-file1.text"
-           "Alice/alice-2/foo-file3.text"
-           "Alice/alice-2/foo-file3.texts"
-           "Alice/alice-3/foo-file4.text"
-           "Bob/alice-3/foo-file4.text"
-           "Bob/bob-1/foo-file1.text"
-           "Bob/bob-1/foo-file2.text"
-           "Bob/bob-2/foo-file1.text"
-           "Bob/bob-2/foo-file5.text"
-           "foo-file1.text"
-           "foo-file3.texts2"
-           )))
-
-  (should (equal
-          (sort (fc-root-rel-all-completions "b" table nil nil) #'string-lessp)
-          nil))
-
-  (let ((completion-ignore-case t))
-    (should (equal
-            (sort (fc-root-rel-all-completions "b" table nil nil) 
#'string-lessp)
-                  (list
-                   "Bob/alice-3/foo-file4.text"
-                   "Bob/bob-1/foo-file1.text"
-                   "Bob/bob-1/foo-file2.text"
-                   "Bob/bob-2/foo-file1.text"
-                   "Bob/bob-2/foo-file5.text"
-                   )))
-    )
-
-  (should (equal
-          (sort (fc-root-rel-all-completions "*/foo" table nil nil) 
#'string-lessp)
-          (list
-           "Alice/alice-1/foo-file1.text"
-           "Alice/alice-1/foo-file2.text"
-           "Alice/alice-2/foo-file1.text"
-           "Alice/alice-2/foo-file3.text"
-           "Alice/alice-2/foo-file3.texts"
-           "Alice/alice-3/foo-file4.text"
-           "Bob/alice-3/foo-file4.text"
-           "Bob/bob-1/foo-file1.text"
-           "Bob/bob-1/foo-file2.text"
-           "Bob/bob-2/foo-file1.text"
-           "Bob/bob-2/foo-file5.text"
-           )))
-
-  (should (equal
-          (sort (fc-root-rel-all-completions "Alice/alice-1/" table nil nil) 
#'string-lessp)
-          (list
-           "Alice/alice-1/bar-file1.text"
-           "Alice/alice-1/bar-file2.text"
-           "Alice/alice-1/foo-file1.text"
-           "Alice/alice-1/foo-file2.text"
-           )))
-
-  (should (equal
-          (sort (fc-root-rel-all-completions "Alice/alice-1/f-file2" table nil 
nil) #'string-lessp)
-          (list
-           "Alice/alice-1/foo-file2.text"
-           )))
-  )
-
-(ert-deftest test-fc-root-rel-all-completions-noface-iter ()
-  (let ((table (apply-partially 'fc-root-rel-completion-table-iter 
fc-root-rel-iter))
-       (completion-category-overrides '(project-file (styles . file-root-rel)))
-       (completion-ignore-case nil))
-    (test-fc-root-rel-all-completions-noface-1 table)))
-
-(ert-deftest test-fc-root-rel-all-completions-noface-list ()
-  (let ((table (apply-partially 'fc-root-rel-completion-table-list 
fc-root-rel-file-list uft-root))
-       (completion-category-overrides '(project-file (styles . file-root-rel)))
-       (completion-ignore-case nil))
-    (test-fc-root-rel-all-completions-noface-1 table)))
-
-(provide 'file-complete-root-relative-test)
-;;; file-complete-root-relative-test.el ends here
diff --git a/packages/uniquify-files/file-complete-root-relative.el 
b/packages/uniquify-files/file-complete-root-relative.el
deleted file mode 100644
index 14d1b1f..0000000
--- a/packages/uniquify-files/file-complete-root-relative.el
+++ /dev/null
@@ -1,324 +0,0 @@
-;;; file-complete-root-relative.el --- Completion style for files  -*- 
lexical-binding:t -*-
-;;
-;; Copyright (C) 2019 Free Software Foundation, Inc.
-;;
-;; Author: Stephen Leake <stephen_le...@stephe-leake.org>
-;; Maintainer: Stephen Leake <stephen_le...@stephe-leake.org>
-;; Keywords: completion
-;; Version: 0
-;; package-requires: ((emacs "25.0"))
-;;
-;; 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 <http://www.gnu.org/licenses/>.
-
-
-;;; Commentary
-
-;; A file completion style in which the root directory is left out of
-;; the completion string displayed to the user.
-;;
-;; Following the Design section in uniquify-files.el, this completion
-;; style has the following string formats:
-;;
-;; - user: file name relative to a root directory
-;;
-;; - completion table input: same as user
-;;
-;; - data: absolute file name
-;;
-;; The completion style requires knowlege of the root directory;
-;; currently, this requires use of a completion function to provide a
-;; place to store it.
-
-(require 'cl-lib)
-
-(require 'file-complete)
-
-(defun fc-root-rel--root (table)
-  "Return root from TABLE."
-  (cdr (assoc 'root (completion-metadata "" table nil))))
-
-(defun fc-root-rel-to-table-input (user-string _table _pred)
-  "Implement `completion-to-table-input' for file-root-rel."
-  user-string)
-
-(defun fc-root-rel-to-data (user-string table _pred)
-  "Implement `completion-get-data-string' for file-root-rel."
-  ;; We assume USER-STRING is complete and unique.
-  (let ((root (fc-root-rel--root table)))
-    (concat root user-string)))
-
-(defun fc-root-rel-to-user (data-string-list root)
-  "Convert DATA-STRING-LIST to list of user format strings."
-  ;; Assume they all start with ROOT, which ends in /
-  (let ((prefix-length (length root)))
-    (mapcar
-     (lambda (abs-file-name)
-       (substring abs-file-name prefix-length))
-     data-string-list)
-  ))
-
-(defun fc-root-rel--pcm-merged-pat (string all point)
-  "Return a pcm pattern that is the merged completion of STRING in ALL.
-ALL must be a list of table input format strings?
-Pattern is in reverse order."
-  (let* ((case-fold-search completion-ignore-case)
-        (completion-pcm--delim-wild-regex
-         (concat "[" completion-pcm-word-delimiters "*]"))
-        (pattern (completion-pcm--string->pattern string point)))
-    (completion-pcm--merge-completions all pattern)
-    ))
-
-(defun fc-root-rel-try-completion (string table pred point)
-  "Implement `completion-try-completion' for file-root-rel."
-  ;; Returns list of user format strings, nil, or t.
-  (let (result
-       rel-all
-       done)
-
-    (setq completion-current-style 'file-root-rel)
-
-    ;; Compute result, set done.
-    (cond
-     ((functionp table)
-      (setq rel-all (fc-root-rel-all-completions string table pred point))
-
-      (cond
-       ((null rel-all) ;; No matches.
-       (setq result nil)
-       (setq done t))
-
-       ((= 1 (length rel-all)) ;; One match; unique.
-       (setq done t)
-
-       ;; Check for valid completion
-       (if (string-equal string (car rel-all))
-           (setq result t)
-
-         (setq result (car rel-all))
-         (setq result (cons result (length result)))))
-
-       (t ;; Multiple matches
-       (setq done nil))
-       ))
-
-     ;; The following cases handle being called from
-     ;; icomplete-completions with the result of `all-completions'
-     ;; instead of the real table function. TABLE is a list of
-     ;; relative file names.
-
-     ((null table) ;; No matches.
-      (setq result nil)
-      (setq done t))
-
-     (t
-      (setq rel-all table)
-      (setq done nil))
-     )
-
-    (if done
-       result
-
-      ;; Find merged completion of relative file names
-      (let* ((merged-pat (fc-root-rel--pcm-merged-pat string rel-all point))
-
-            ;; `merged-pat' is in reverse order.  Place new point at:
-            (point-pat (or (memq 'point merged-pat) ;; the old point
-                           (memq 'any   merged-pat) ;; a place where there's 
something to choose
-                           (memq 'star  merged-pat) ;; ""
-                           merged-pat))             ;; the end
-
-            ;; `merged-pat' does not contain 'point when the field
-            ;; containing 'point is fully completed.
-
-            (new-point (length (completion-pcm--pattern->string point-pat)))
-
-            ;; Compute this after `new-point' because `nreverse'
-            ;; changes `point-pat' by side effect.
-            (merged (completion-pcm--pattern->string (nreverse merged-pat))))
-
-       (cons merged new-point)))
-   ))
-
-(defun fc-root-rel--hilit (string all point)
-  "Apply face text properties to each element of ALL.
-STRING is the current user input.
-ALL is a list of strings in user format.
-POINT is the position of point in STRING.
-Returns new list.
-
-Adds the face `completions-first-difference' to the first
-character after each completion field."
-  (let* ((merged-pat (nreverse (fc-root-rel--pcm-merged-pat string all point)))
-        (field-count 0)
-        (regex (completion-pcm--pattern->regex merged-pat '(any star any-delim 
point)))
-        )
-    (dolist (x merged-pat)
-      (when (not (stringp x))
-       (setq field-count (1+ field-count))))
-
-    (mapcar
-     (lambda (str)
-       (when (string-match regex str)
-        (cl-loop
-         for i from 1 to field-count
-         do
-         (when (and
-                (match-beginning i)
-                (<= (1+ (match-beginning i)) (length str)))
-           (put-text-property (match-beginning i) (1+ (match-beginning i)) 
'face 'completions-first-difference str))
-         ))
-       str)
-     all)))
-
-(defun fc-root-rel-all-completions (user-string table pred point)
-  "Implement `completion-all-completions' for root-relative."
-  ;; Returns list of data format strings (abs file names).
-
-  (setq completion-current-style 'file-root-rel)
-
-  ;; Note that we never get here with TABLE a list of filenames.
-  (let* ((table-string (fc-root-rel-to-table-input user-string table pred))
-        (all (funcall table table-string pred t)))
-
-    (when all
-      (setq all (fc-root-rel-to-user all (fc-root-rel--root table)))
-      (setq all (fc-root-rel--hilit user-string all point))
-      all
-      )))
-
-(defun fc-root-rel-completion-table-iter (path-iter string pred action)
-  "Implement a completion table for file names in PATH-ITER.
-
-PATH-ITER is a `path-iterator' object; it must have exacly one
-recursive root, and no non-recursive roots.
-
-STRING, PRED, ACTION are completion table arguments."
-
-  (let ((root (car (path-iter-path-recursive-init path-iter))))
-    (cond
-     ((eq action 'metadata)
-      (cons 'metadata
-           (list
-            '(category . project-file)
-            '(styles . (file-root-rel))
-            (cons 'root root))))
-
-     (t
-      (file-complete-completion-table path-iter 'root-relative root string 
pred action))
-     )))
-
-(defun fc-root-rel--pcm-regex-list (string root)
-  "Return pcm regex constructed from STRING (a table format string)."
-  (let ((pattern (completion-pcm--string->pattern string)))
-    (concat "\\`"
-           root
-           (substring (completion-pcm--pattern->regex pattern) 2);; trim \`
-           )))
-
-(defun fc-root-rel-completion-table-list (file-list root string pred action)
-  "Implement a completion table for file names in FILE-LIST,
-with common prefix ROOT.
-
-STRING, PRED, ACTION are completion table arguments."
-
-  ;; This completion table function is required to provide access to
-  ;; ROOT via metadata, and the file-root-rel suggested style.
-
-  ;; `completion-to-table-input' doesn't realize we are dealing with a
-  ;; list, so we have to convert to abs file name.
-  (setq root (file-name-as-directory root))
-  (let ((abs-name (concat (file-name-as-directory root) string)))
-
-    (cond
-     ((eq (car-safe action) 'boundaries)
-      ;; We don't use boundaries; return the default definition.
-      (cons 'boundaries
-           (cons 0 (length (cdr action)))))
-
-     ((eq action 'metadata)
-      (cons 'metadata
-              (list
-               '(category . project-file)
-               '(styles . (file-root-rel))
-               (cons 'root (file-name-as-directory root)))))
-
-     ((memq action
-           '(nil    ;; Called from `try-completion'
-             lambda ;; Called from `test-completion'
-             t))    ;; Called from all-completions
-
-      (let ((regex (fc-root-rel--pcm-regex-list string root))
-           (case-fold-search completion-ignore-case)
-           (result nil))
-       (dolist (abs-file-name file-list)
-         (when (and
-                (string-match regex abs-file-name)
-                (or (null pred)
-                    (funcall pred abs-file-name)))
-           (push abs-file-name result)))
-
-       (cond
-        ((null action)
-         (try-completion abs-name result))
-
-        ((eq 'lambda action)
-         (test-completion abs-name file-list pred))
-
-        ((eq t action)
-         result)
-        )))
-     )))
-
-(add-to-list 'completion-styles-alist
-            '(file-root-rel
-              fc-root-rel-try-completion
-              fc-root-rel-all-completions
-              "root relative hierarchical filenames."
-              fc-root-rel-to-table-input    ;; 4 user to table input format
-              fc-root-rel-to-data)) ;; 5 user to data format
-
-(defun locate-root-rel-file-iter (iter &optional predicate default prompt)
-  "Return an absolute filename, with file-root-rel completion style.
-ITER is a path-iterator giving the directory path to search; it
-must have exacly one recursive root, and no non-recursive roots.
-If PREDICATE is nil, it is ignored. If non-nil, it must be a
-function that takes one argument; the absolute file name.  The
-file name is included in the result if PRED returns
-non-nil. DEFAULT is the default for completion.
-
-In the user input string, `*' is treated as a wildcard."
-  (let* ((table (apply-partially #'fc-root-rel-completion-table-iter iter))
-        (table-styles (cdr (assq 'styles (completion-metadata "" table nil))))
-        (completion-category-overrides
-         (list (list 'project-file (cons 'styles table-styles)))))
-
-    (unless (and (= 0 (length (path-iter-path-non-recursive-init iter)))
-                (= 1 (length (path-iter-path-recursive-init iter))))
-      (user-error "iterator does not have exactly one recursive root"))
-
-    (completing-read (format (concat (or prompt "file") " (%s): ") default)
-                    table
-                    predicate t nil nil default)
-    ))
-
-;; For example:
-;; (locate-root-rel-file-iter
-;;  (make-path-iterator
-;;   :user-path-non-recursive nil
-;;   :user-path-recursive 
"c:/Projects/elpa/packages/uniquify-files/uniquify-files-resources"))
-
-(provide 'file-complete-root-relative)
-;;; file-complete-root-relative.el ends here
diff --git a/packages/uniquify-files/file-complete.el 
b/packages/uniquify-files/file-complete.el
deleted file mode 100644
index 5a498e8..0000000
--- a/packages/uniquify-files/file-complete.el
+++ /dev/null
@@ -1,192 +0,0 @@
-;;; file-complete.el --- core utilities for various file-completion styles and 
tables.  -*-lexical-binding:t-*-
-
-(defconst file-complete-match-styles '(absolute root-relative basename)
-  "Filename matching styles supported by `file-complete-completion-table'.
-
-- absolute - match entire string against absolute file names,
-  anchored at the string beginning.
-
-- root-relative - match entire string against file name relative
-  to a constant root.
-
-- basename - match basename portion of string against basename
-  portion of file names, and also directory name portions, not anchored.
-  For example, \"foo/c\" will match \"/root/foo/bar/car.text\".")
-
-(defun file-complete--iter-pcm-regex (string match-style root)
-  "Return dir and file regexes constructed from STRING (a partial file name)."
-  ;; `file-complete-completion-table' matches against directories from a
-  ;; `path-iterator', and files within those directories. Thus we
-  ;; construct two regexps from `string'.
-  (let* ((dir-name (file-name-directory string)) ;; nil, or ends in /
-        (file-name (file-name-nondirectory string))
-
-        (file-pattern (completion-pcm--string->pattern file-name))
-        (file-regex (completion-pcm--pattern->regex file-pattern))
-
-        (dir-pattern (and dir-name (completion-pcm--string->pattern dir-name)))
-
-        (dir-regex
-         (cl-ecase match-style
-           (absolute
-            (completion-pcm--pattern->regex dir-pattern))
-
-           (root-relative
-            (cond
-             ((null dir-name)
-              (if (= 0 (length file-name))
-                  (concat "\\`" root)
-                (concat "\\`" root
-                        (when (eq (car file-pattern) 'star) ".*?")
-                        "\\(" (substring
-                               (completion-pcm--pattern->regex
-                                (append file-pattern (list 'star)))
-                               2) ;; strip \`
-                        "\\)?\\'")))
-
-             (t
-              (concat root
-                      (substring (completion-pcm--pattern->regex dir-pattern) 
2) ;; strip \`
-                      (if (= 0 (length file-name))
-                          ""
-                        (concat
-                         "\\("
-                         ;; The non-directory portion of STRING may
-                         ;; be intended to match the next directory
-                         ;; level.
-                         (substring (completion-pcm--pattern->regex 
file-pattern) 2) ;; strip \`
-                         "\\)?"))))
-             ))
-
-           (basename
-            (substring (completion-pcm--pattern->regex dir-pattern) 2)) ;; 
strip \`
-           )))
-    (list dir-regex file-regex)))
-
-(defun file-complete-completion-table (path-iter match-style root string pred 
action)
-  "Implement a completion table for file names in PATH-ITER.
-
-PATH-ITER is a `path-iterator' object. It will be restarted for
-each call to `file-complete-completion-table'.
-
-MATCH-STYLE is one of `file-complete-match-styles', which see.
-ROOT is only non-nil for root-relative.
-
-STRING, PRED, ACTION are completion table arguments:
-
-STRING is a partial file name.  `*' is treated as a wildcard, as
-in a shell glob pattern.
-
-If PRED is nil, it is ignored. If non-nil, it must be a function
-that takes one argument; the absolute file name.  The file name
-is included in the result if PRED returns non-nil. In either
-case, `completion-ignored-extensions', `completion-regexp-list',
-`completion-ignore-case' are used as described in
-`file-name-all-completions'.
-
-ACTION is the current completion action; one of:
-
-- nil; return common prefix of all completions of STRING, nil or
-  t; see `try-completion'.
-
-- t; return all completions; see `all-completions'
-
-- lambda; return non-nil if string is a valid completion; see
-  `test-completion'.
-
-- '(boundaries . SUFFIX); return the completion region
-  '(boundaries START . END) within STRING; see
-  `completion-boundaries'.
-
-- 'metadata; return (metadata . ALIST) as defined by
-  `completion-metadata'."
-
-  (cl-assert (memq match-style file-complete-match-styles))
-
-  (cond
-   ((eq (car-safe action) 'boundaries)
-    ;; We don't use boundaries; return the default definition.
-    (cons 'boundaries
-         (cons 0 (length (cdr action)))))
-
-   ((eq action 'metadata)
-    (cons 'metadata
-         (list
-          '(category . project-file)
-          )))
-
-   ((memq action
-         '(nil    ;; Called from `try-completion'.
-           lambda ;; Called from `test-completion'.
-            t))   ;; Called from `all-completions'.
-
-    ;; In file-name-all-completions, `completion-regexp-list', is
-    ;; matched against file names and directories relative to `dir'.
-    ;; Thus to handle partial completion delimiters in `string', we
-    ;; construct two regexps from `string'; one from the directory
-    ;; portion, and one from the non-directory portion.  We use the
-    ;; directory regexp here, and pass the non-directory regexp to
-    ;; `file-name-all-completions' via `completion-regexp-list'.  The
-    ;; `string' input to `file-name-all-completions' is redundant with
-    ;; the regexp, so we always build a regexp, and pass an empty
-    ;; string.
-
-    (pcase-let ((`(,dir-regex ,file-regex)
-                (file-complete--iter-pcm-regex string match-style root)))
-      (let ((result nil))
-
-       (path-iter-restart path-iter)
-
-       (let ((case-fold-search completion-ignore-case)
-             dir)
-         (while (setq dir (path-iter-next path-iter))
-           (when (string-match dir-regex dir)
-             ;; A project that deals only with C files might set
-             ;; `completion-regexp-list' to match only *.c, *.h, so we
-             ;; preserve that here.
-             (let ((completion-regexp-list
-                    (if (match-string 1 dir)
-                        ;; Non-directory portion of STRING matches
-                        ;; dir, so don't match it against files in
-                        ;; dir.
-                        completion-regexp-list
-                      (cons file-regex completion-regexp-list))))
-               (cl-mapc
-                (lambda (file-name)
-                  (let ((absfile (concat (file-name-as-directory dir) 
file-name)))
-                    (when (and (not (directory-name-p file-name))
-                               (or (null pred)
-                                   (funcall pred absfile)))
-                      (push absfile result))))
-                (file-name-all-completions "" dir))
-               ))
-           ))
-       (cond
-        ((null action)
-         ;; Called from `try-completion'; find common prefix of `result'.
-         (try-completion "" result))
-
-         ((eq action 'lambda)
-         ;; Called from `test-completion'. Note that this call
-         ;; includes the `completion-to-table-input' advice, which in
-         ;; this case converts STRING to data format (= absolute file
-         ;; name).  But that fails for root-relative match-style,
-         ;; because the result list does not know about ROOT.  So we
-         ;; have to handle that here.
-         (cl-case match-style
-           ((absolute basename)
-            (test-completion string result))
-
-           (root-relative
-            (test-completion (concat root string) result))
-           ))
-
-        ((eq action t)
-         ;; Called from all-completions
-         result)
-        ))
-      ))
-   ))
-
-(provide 'file-complete)
-;; file-complete.el ends here.
diff --git 
a/packages/uniquify-files/uniquify-files-resources/wisitoken-generate-packrat-test.text
 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-generate-packrat-test.text
new file mode 100644
index 0000000..988f655
--- /dev/null
+++ 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-generate-packrat-test.text
@@ -0,0 +1 @@
+Wisitoken-generate-packrat-test.text
diff --git 
a/packages/uniquify-files/uniquify-files-resources/wisitoken-syntax_trees-test.text
 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-syntax_trees-test.text
new file mode 100644
index 0000000..5035ff7
--- /dev/null
+++ 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-syntax_trees-test.text
@@ -0,0 +1 @@
+Wisitoken-syntax_trees-test.text
diff --git 
a/packages/uniquify-files/uniquify-files-resources/wisitoken-text_io_trace.text 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-text_io_trace.text
new file mode 100644
index 0000000..a2d8f82
--- /dev/null
+++ 
b/packages/uniquify-files/uniquify-files-resources/wisitoken-text_io_trace.text
@@ -0,0 +1 @@
+Wisitoken-text_io_trace.text
diff --git a/packages/uniquify-files/uniquify-files-test.el 
b/packages/uniquify-files/uniquify-files-test.el
index 59968d0..a75638c 100644
--- a/packages/uniquify-files/uniquify-files-test.el
+++ b/packages/uniquify-files/uniquify-files-test.el
@@ -26,28 +26,9 @@
 ;; completion functions interact with completing-read is not fully
 ;; tested. The following table gives useful test cases for a manual
 ;; interactive test (copy it to an org-mode buffer).
-;;
-;; | input                                         | display                   
                                               | result                         
     | works/comment                                 |
-;; 
|-----------------------------------------------+--------------------------------------------------------------------------+-------------------------------------+-----------------------------------------------|
-;; | "f-file1" <ret>                               | 
f-file1(foo-file1.text<){*>*, *A*lice/alice-1/>, *A*lice/alice-2>, ... } | 
<root>/foo-file1.text               | works                                     
    |
-;; | "f-file1" <right> <ret>                       | 
f-file1(foo-file1.text<){*Alice/alice-1/>*. *A*lice/alice-2/>, ... }     | 
<root>/Alice/alice-1/foo-file1.text | works                                     
    |
-;; | "f-file1" <right> <tab> <ret>                 | foo-file1.text<{*>*. 
*A*lice/alice-1/>. *A*lice/alice-2/>, ... }         | <root>/foo-file1.text     
          | works                                         |
-;; | "f-file1" <tab> <tab> <ret>                   | shows *Completion* buffer 
                                               | <root>/foo-file1.text          
     | works                                         |
-;; | "f-file1" <C-tab> <C-tab> <ret>               | cycles foo-file1.text<> 
[Matched]                                        | 
<root>/Alice/alice-1foo-file1.text  | works                                     
    |
-;; | "f-file1<a-2" <ret>                           | f-file1<a-2 [Matched]     
                                               | 
<root>/Alice/alice-2/foo-file1.text | works                                     
    |
-;; | "b-file2" <tab> <ret>                         | 
bar-file2.text<./alice-{*1*/> *2*/>}                                     | 
<root>/Alice/alice-1/bar-file2.text | works except display has bad glyph 
(./alice-) |
-;; | "b-file2" <tab> <tab> <ret>                   | 
bar-file2.text<Alice/alice-{1/> 2/>}                                     | ""   
                               | works                                         |
-;; | "b-file2" <tab> <tab> <tab> <ret>             | shows *Completion* buffer 
                                               | ""                             
     | works                                         |
-;; | "f-file3" <ret>                               | f-file3(foo-file3.text) 
[Matched]                                        | 
<root>/Alice/alice-2/foo-file3.text | works                                     
    |
-;; | "f-file3" <tab> <ret>                         | foo-file3.text [Matched]  
                                               | 
<root>/Alice/alice-2/foo-file3.text | works                                     
    |
-;; | "fil"                                         | fil (No matches)          
                                               | -                              
     | works                                         |
-;; | "*-file1" <tab> <ret>                         | 
*-file1.text<{*f*oo-file1.text<*A*lice/alice-2/> ... }                   | 
<root>/Alice/alice-2/foo-file1.text | works                                     
    |
-;; | "*-file1" <tab> A <tab> 1 <tab> <ret>         | 
*^-file1.text<Alice/alice-1/>{*bar-file1.text<Alice/alice-1/>*, ...}     | 
<root>/Alice/alice-1/bar-file1.text | works                                     
    |
-;; | "*-file1" <tab> A <tab> 1 <tab> <del> f <tab> | 
foo-file1.text<Alice/alice-1/> [Matched]                                 | 
<root>/Alice/alice-1/foo-file1.text | works                                     
    |
-;; | "foo-file1.text<Alice/alice-1> <ret>          | 
foo-file1.text<Alice/alice-1(/>) [Matched]                               | ""   
                               | works                                         |
-
-
-;; See `test-uniquify-file-all-completions-face' below for an explanation of 
`no-byte-compile'.
+
+;; See `test-uniquify-file-all-completions-face' below for an
+;; explanation of `no-byte-compile'.
 
 (require 'ert)
 (require 'uniquify-files)
@@ -66,9 +47,7 @@
 (defconst uft-bob1 (concat uft-root "/Bob/bob-1"))
 (defconst uft-bob2 (concat uft-root "/Bob/bob-2"))
 
-(defconst uft-iter
-  (make-path-iterator
-   :user-path-non-recursive
+(defconst uft-path
    (list uft-root
         (concat uft-root "/Alice")
         uft-alice1
@@ -77,267 +56,220 @@
         (concat uft-root "/Bob")
         uft-Bob-alice3
         uft-bob1
-        uft-bob2)))
+        uft-bob2))
+
+(defun uft-table ()
+  (let (files)
+    (dolist (dir uft-path)
+      (mapc
+       (lambda (absfile)
+        (when (and (not (string-equal "." (substring absfile -1)))
+                   (not (string-equal ".." (substring absfile -2)))
+                   (not (file-directory-p absfile)))
+          (push absfile files)))
+       (directory-files dir t)))
+    (apply-partially 'uniq-file-completion-table (uniq-file-uniquify files))))
+
+(ert-deftest test-uniq-file-test-completion ()
+  (let ((table (uft-table)))
+    (should (equal (test-completion "foo-fi" table)
+                  nil))
 
+    (should (equal (test-completion "f-fi<dir" table)
+                  nil))
 
-(defun test-uniq-file-test-completion-1 (table)
-  (should (equal (test-completion "foo-fi" table)
-                nil))
+    (should (equal (test-completion "foo-file1.text<>" table)
+                  t))
 
-  (should (equal (test-completion "f-fi<dir" table)
-                nil))
+    (should (equal (test-completion "foo-file1.text" table)
+                  nil))
 
-  (should (equal (test-completion "foo-file1.text<>" table)
-                t))
+    (should (equal (test-completion "foo-file1.text<Alice/alice-1/>" table)
+                  t))
 
-  (should (equal (test-completion "foo-file1.text" table)
-                t))
+    (should (equal (test-completion "foo-file3.tex" table) ;; partial file name
+                  nil))
+
+    (should (equal (test-completion "foo-file3.texts2" table)
+                  t))
 
-  (should (equal (test-completion "foo-file1.text<alice-1/>" table)
-                t))
+    (should (equal (test-completion "bar-file2.text<Alice/alice-" table)
+                  nil))
+    ))
 
-  (should (equal (test-completion "foo-file3.tex" table) ;; partial file name
-                nil))
+(ert-deftest test-uniq-file-all-completions-noface ()
+  (let ((table (uft-table))
+       (completion-ignore-case nil))
+    (should (equal
+            (sort (uniq-file-all-completions "" table nil nil) #'string-lessp)
+            (list
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
+             "foo-file1.text<>"
+             "foo-file1.text<Alice/alice-1/>"
+             "foo-file1.text<Alice/alice-2/>"
+             "foo-file1.text<Bob/bob-1/>"
+             "foo-file1.text<Bob/bob-2/>"
+             "foo-file2.text<Alice/alice-1/>"
+             "foo-file2.text<Bob/bob-1/>"
+             "foo-file3.text"
+             "foo-file3.texts"
+             "foo-file3.texts2"
+             "foo-file4.text<Alice/alice-3/>"
+             "foo-file4.text<Bob/alice-3/>"
+             "foo-file5.text"
+              "wisitoken-generate-packrat-test.text"
+              "wisitoken-syntax_trees-test.text"
+              "wisitoken-text_io_trace.text"
+             )))
 
-  (should (equal (test-completion "foo-file3.texts2" table)
-                t))
+    (should (equal
+            (sort (uniq-file-all-completions "*-fi" table nil nil) 
#'string-lessp)
+            (list
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
+             "foo-file1.text<>"
+             "foo-file1.text<Alice/alice-1/>"
+             "foo-file1.text<Alice/alice-2/>"
+             "foo-file1.text<Bob/bob-1/>"
+             "foo-file1.text<Bob/bob-2/>"
+             "foo-file2.text<Alice/alice-1/>"
+             "foo-file2.text<Bob/bob-1/>"
+             "foo-file3.text"
+             "foo-file3.texts"
+             "foo-file3.texts2"
+             "foo-file4.text<Alice/alice-3/>"
+             "foo-file4.text<Bob/alice-3/>"
+             "foo-file5.text"
+             )))
 
-  (should (equal (test-completion "bar-file2.text<Alice/alice-" table)
-                nil))
-  )
+    (should (equal
+            (sort (uniq-file-all-completions "a" table nil nil) #'string-lessp)
+            ;; Should _not_ match directory names
+            nil))
 
-(ert-deftest test-uniq-file-test-completion-func ()
-  (let ((table (apply-partially 'uniq-file-completion-table uft-iter))
-       (completion-current-style 'uniquify-file))
-    (test-uniq-file-test-completion-1 table)))
-
-(ert-deftest test-uniq-file-test-completion-list ()
-  (let ((table (path-iter-all-files uft-iter))
-       (completion-styles '(uniquify-file))) ;; FIXME: need a way to specify 
category
-    (test-uniq-file-test-completion-1 table)))
-
-(defun test-uniq-file-all-completions-noface-1 (table)
-  (should (equal
-          (sort (uniq-file-all-completions "" table nil nil) #'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           "foo-file1.text<>"
-           "foo-file1.text<Alice/alice-1/>"
-           "foo-file1.text<Alice/alice-2/>"
-           "foo-file1.text<Bob/bob-1/>"
-           "foo-file1.text<Bob/bob-2/>"
-           "foo-file2.text<Alice/alice-1/>"
-           "foo-file2.text<Bob/bob-1/>"
-           "foo-file3.text"
-           "foo-file3.texts"
-           "foo-file3.texts2"
-           "foo-file4.text<Alice/alice-3/>"
-           "foo-file4.text<Bob/alice-3/>"
-           "foo-file5.text"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "*-fi" table nil nil) 
#'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           "foo-file1.text<>"
-           "foo-file1.text<Alice/alice-1/>"
-           "foo-file1.text<Alice/alice-2/>"
-           "foo-file1.text<Bob/bob-1/>"
-           "foo-file1.text<Bob/bob-2/>"
-           "foo-file2.text<Alice/alice-1/>"
-           "foo-file2.text<Bob/bob-1/>"
-           "foo-file3.text"
-           "foo-file3.texts"
-           "foo-file3.texts2"
-           "foo-file4.text<Alice/alice-3/>"
-           "foo-file4.text<Bob/alice-3/>"
-           "foo-file5.text"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "a" table nil nil) #'string-lessp)
-          ;; Should _not_ match directory names
-          nil))
-
-  (should (equal
-          (sort (uniq-file-all-completions "b" table nil nil) #'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "foo" table nil nil) #'string-lessp)
-          (list
-           "foo-file1.text<>"
-           "foo-file1.text<Alice/alice-1/>"
-           "foo-file1.text<Alice/alice-2/>"
-           "foo-file1.text<Bob/bob-1/>"
-           "foo-file1.text<Bob/bob-2/>"
-           "foo-file2.text<Alice/alice-1/>"
-           "foo-file2.text<Bob/bob-1/>"
-           "foo-file3.text"
-           "foo-file3.texts"
-           "foo-file3.texts2"
-           "foo-file4.text<Alice/alice-3/>"
-           "foo-file4.text<Bob/alice-3/>"
-           "foo-file5.text"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "f-file2" table nil nil) 
#'string-lessp)
-          (list
-           "foo-file2.text<Alice/alice-1/>"
-           "foo-file2.text<Bob/bob-1/>"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "b-fi<" table nil nil) 
#'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "f-file<" table nil nil) 
#'string-lessp)
-          (list
-           "foo-file1.text<>"
-           "foo-file1.text<Alice/alice-1/>"
-           "foo-file1.text<Alice/alice-2/>"
-           "foo-file1.text<Bob/bob-1/>"
-           "foo-file1.text<Bob/bob-2/>"
-           "foo-file2.text<Alice/alice-1/>"
-           "foo-file2.text<Bob/bob-1/>"
-           "foo-file3.text"
-           "foo-file3.texts"
-           "foo-file3.texts2"
-           "foo-file4.text<Alice/alice-3/>"
-           "foo-file4.text<Bob/alice-3/>"
-           "foo-file5.text"
-           )))
-
-  (should (equal
-          (sort (uniq-file-all-completions "b-fi<a-" table nil nil) 
#'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           )))
-
-  (let ((completion-ignore-case t))
     (should (equal
-            (sort (uniq-file-all-completions "b-fi<a-" table nil nil) 
#'string-lessp)
+            (sort (uniq-file-all-completions "b" table nil nil) #'string-lessp)
             (list
-             "bar-file1.text<Alice/alice-1/>"
-             "bar-file1.text<Alice/alice-2/>"
-             "bar-file2.text<Alice/alice-1/>"
-             "bar-file2.text<Alice/alice-2/>"
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
              )))
-    )
 
-  (should (equal
-          (sort (uniq-file-all-completions "b-fi<a-1" table nil nil) 
#'string-lessp)
-          (list "bar-file1.text<alice-1/>"
-                "bar-file2.text<alice-1/>")))
+    (should (equal
+            (sort (uniq-file-all-completions "foo" table nil nil) 
#'string-lessp)
+            (list
+             "foo-file1.text<>"
+             "foo-file1.text<Alice/alice-1/>"
+             "foo-file1.text<Alice/alice-2/>"
+             "foo-file1.text<Bob/bob-1/>"
+             "foo-file1.text<Bob/bob-2/>"
+             "foo-file2.text<Alice/alice-1/>"
+             "foo-file2.text<Bob/bob-1/>"
+             "foo-file3.text"
+             "foo-file3.texts"
+             "foo-file3.texts2"
+             "foo-file4.text<Alice/alice-3/>"
+             "foo-file4.text<Bob/alice-3/>"
+             "foo-file5.text"
+             )))
 
-  (let ((completion-ignore-case t))
     (should (equal
-            (sort (uniq-file-all-completions "b-fi<a-1" table nil nil) 
#'string-lessp)
-            (list "bar-file1.text<Alice/alice-1/>"
-                  "bar-file2.text<Alice/alice-1/>")))
-    )
+            (sort (uniq-file-all-completions "f-file2" table nil nil) 
#'string-lessp)
+            (list
+             "foo-file2.text<Alice/alice-1/>"
+             "foo-file2.text<Bob/bob-1/>"
+             )))
 
-  (should (equal (uniq-file-all-completions "f-file1.text<a-1" table nil nil)
-                ;; Accidentally match "a" with "packages"
-                (list "foo-file1.text<Alice/alice-1/>")))
+    (should (equal
+            (sort (uniq-file-all-completions "b-fi<" table nil nil) 
#'string-lessp)
+            (list
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
+             )))
+
+    (should (equal
+            (sort (uniq-file-all-completions "f-file<" table nil nil) 
#'string-lessp)
+            (list
+             "foo-file1.text<>"
+             "foo-file1.text<Alice/alice-1/>"
+             "foo-file1.text<Alice/alice-2/>"
+             "foo-file1.text<Bob/bob-1/>"
+             "foo-file1.text<Bob/bob-2/>"
+             "foo-file2.text<Alice/alice-1/>"
+             "foo-file2.text<Bob/bob-1/>"
+             "foo-file3.text"
+             "foo-file3.texts"
+             "foo-file3.texts2"
+             "foo-file4.text<Alice/alice-3/>"
+             "foo-file4.text<Bob/alice-3/>"
+             "foo-file5.text"
+             )))
+
+    (should (equal
+            (sort (uniq-file-all-completions "b-fi<a-" table nil nil) 
#'string-lessp)
+            (list
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
+             )))
+
+    (should (equal
+            (sort (uniq-file-all-completions "b-fi<a-1" table nil nil) 
#'string-lessp)
+            (list "bar-file1.text<alice-1/>"
+                  "bar-file2.text<alice-1/>")))
 
-  (let ((completion-ignore-case t))
     (should (equal (uniq-file-all-completions "f-file1.text<a-1" table nil nil)
                   (list "foo-file1.text<Alice/alice-1/>")))
-    )
 
-  (should (equal (sort (uniq-file-all-completions "f-file1.text<al" table nil 
nil) #'string-lessp)
-                (list
-                 "foo-file1.text<alice-1/>"
-                 "foo-file1.text<alice-2/>")))
-
-  (let ((completion-ignore-case t))
     (should (equal (sort (uniq-file-all-completions "f-file1.text<al" table 
nil nil) #'string-lessp)
                   (list
                    "foo-file1.text<Alice/alice-1/>"
                    "foo-file1.text<Alice/alice-2/>")))
-    )
-
-  (should (equal (sort (uniq-file-all-completions "f-file4.text<a-3" table nil 
nil) #'string-lessp)
-                (list
-                 "foo-file4.text<Alice/alice-3/>"
-                 "foo-file4.text<Bob/alice-3/>")))
 
-  (should (equal (sort (uniq-file-all-completions "foo-file4.text<Bob" table 
nil nil) #'string-lessp)
-                (list
-                 "foo-file4.text<Bob/alice-3/>")))
+    (should (equal (sort (uniq-file-all-completions "f-file4.text<a-3" table 
nil nil) #'string-lessp)
+                  (list
+                   "foo-file4.text<Alice/alice-3/>"
+                   "foo-file4.text<Bob/alice-3/>")))
 
-  (should (equal (uniq-file-all-completions "f-file5" table nil nil)
-                (list "foo-file5.text")))
+    (should (equal (sort (uniq-file-all-completions "foo-file4.text<Bob" table 
nil nil) #'string-lessp)
+                  (list
+                   "foo-file4.text<Bob/alice-3/>")))
 
-  (should (equal (uniq-file-all-completions "foo-file1.text<Alice/alice-1/>" 
table nil nil)
-                (list "foo-file1.text<Alice/alice-1/>")))
+    (should (equal (uniq-file-all-completions "f-file5" table nil nil)
+                  (list "foo-file5.text")))
 
-  (should (equal
-          (sort (uniq-file-all-completions "b-fi<a>" table nil nil) 
#'string-lessp)
-          (list
-           "bar-file1.text<alice-1/>"
-           "bar-file1.text<alice-2/>"
-           "bar-file2.text<alice-1/>"
-           "bar-file2.text<alice-2/>"
-           )))
+    (should (equal (uniq-file-all-completions "foo-file1.text<Alice/alice-1/>" 
table nil nil)
+                  (list "foo-file1.text<Alice/alice-1/>")))
 
-  (let ((completion-ignore-case t))
     (should (equal
             (sort (uniq-file-all-completions "b-fi<a>" table nil nil) 
#'string-lessp)
             (list
-             "bar-file1.text<Alice/alice-1/>"
-             "bar-file1.text<Alice/alice-2/>"
-             "bar-file2.text<Alice/alice-1/>"
-             "bar-file2.text<Alice/alice-2/>"
+             "bar-file1.text<alice-1/>"
+             "bar-file1.text<alice-2/>"
+             "bar-file2.text<alice-1/>"
+             "bar-file2.text<alice-2/>"
              )))
-    )
-
-  (should (equal
-          (sort (uniq-file-all-completions "foo-file1.text<>" table nil nil) 
#'string-lessp)
-          ;; This is complete but not unique, because the directory part 
matches multiple directories.
-          (list
-           "foo-file1.text<>"
-           "foo-file1.text<Alice/alice-1/>"
-           "foo-file1.text<Alice/alice-2/>"
-           "foo-file1.text<Bob/bob-1/>"
-           "foo-file1.text<Bob/bob-2/>"
-           )))
-  )
 
-(ert-deftest test-uniq-file-all-completions-noface-func ()
-  (let ((table (apply-partially 'uniq-file-completion-table uft-iter))
-       (completion-current-style 'uniquify-file)
-       (completion-ignore-case nil))
-    (test-uniq-file-all-completions-noface-1 table)))
-
-(ert-deftest test-uniq-file-all-completions-noface-list ()
-  (let ((table (path-iter-all-files uft-iter))
-       (completion-ignore-case nil)
-       (completion-styles '(uniquify-file))) ;; FIXME: need a way to specify 
category
-    (test-uniq-file-all-completions-noface-1 table)))
+    (should (equal
+            (sort (uniq-file-all-completions "foo-file1.text<>" table nil nil) 
#'string-lessp)
+            ;; This is complete but not unique, because the directory part 
matches multiple directories.
+            (list
+             "foo-file1.text<>"
+             "foo-file1.text<Alice/alice-1/>"
+             "foo-file1.text<Alice/alice-2/>"
+             "foo-file1.text<Bob/bob-1/>"
+             "foo-file1.text<Bob/bob-2/>"
+             )))
+    ))
 
 (defun test-uniq-file-hilit (pos-list string)
   "Set 'face text property to 'completions-first-difference at
@@ -348,62 +280,17 @@ all positions in POS-LIST in STRING; return new string."
   string)
 
 (ert-deftest test-uniq-file-all-completions-face ()
-  ;; all-completions tested above without considering face text
+  ;; `all-completions' tested above without considering face text
   ;; properties; here we test just those properties. Test cases are
   ;; the same as above.
   ;;
   ;; WORKAROUND: byte-compiling this test makes it fail; it appears to be
   ;; sharing strings that should not be shared because they have
   ;; different text properties.
-  (let ((table (apply-partially 'uniq-file-completion-table uft-iter))
-       (completion-current-style 'uniquify-file)
+  (let ((table (uft-table))
        (completion-ignore-case nil))
 
     (should (equal-including-properties
-            (sort (uniq-file-all-completions "" table nil nil) #'string-lessp)
-            (list
-             (test-uniq-file-hilit '(0) "bar-file1.text<alice-1/>")
-             (test-uniq-file-hilit '(0) "bar-file1.text<alice-2/>")
-             (test-uniq-file-hilit '(0) "bar-file2.text<alice-1/>")
-             (test-uniq-file-hilit '(0) "bar-file2.text<alice-2/>")
-             (test-uniq-file-hilit '(0) "foo-file1.text<>")
-             (test-uniq-file-hilit '(0) "foo-file1.text<Alice/alice-1/>")
-             (test-uniq-file-hilit '(0) "foo-file1.text<Alice/alice-2/>")
-             (test-uniq-file-hilit '(0) "foo-file1.text<Bob/bob-1/>")
-             (test-uniq-file-hilit '(0) "foo-file1.text<Bob/bob-2/>")
-             (test-uniq-file-hilit '(0) "foo-file2.text<Alice/alice-1/>")
-             (test-uniq-file-hilit '(0) "foo-file2.text<Bob/bob-1/>")
-             (test-uniq-file-hilit '(0) "foo-file3.text")
-             (test-uniq-file-hilit '(0) "foo-file3.texts")
-             (test-uniq-file-hilit '(0) "foo-file3.texts2")
-             (test-uniq-file-hilit '(0) "foo-file4.text<Alice/alice-3/>")
-             (test-uniq-file-hilit '(0) "foo-file4.text<Bob/alice-3/>")
-             (test-uniq-file-hilit '(0) "foo-file5.text")
-             )))
-
-    (should (equal-including-properties
-            (sort (uniq-file-all-completions "*-fi" table nil nil) 
#'string-lessp)
-            (list
-             (test-uniq-file-hilit '(0 8) "bar-file1.text<alice-1/>")
-             (test-uniq-file-hilit '(0 8) "bar-file1.text<alice-2/>")
-             (test-uniq-file-hilit '(0 8) "bar-file2.text<alice-1/>")
-             (test-uniq-file-hilit '(0 8) "bar-file2.text<alice-2/>")
-             (test-uniq-file-hilit '(0 8) "foo-file1.text<>")
-             (test-uniq-file-hilit '(0 8) "foo-file1.text<Alice/alice-1/>")
-             (test-uniq-file-hilit '(0 8) "foo-file1.text<Alice/alice-2/>")
-             (test-uniq-file-hilit '(0 8) "foo-file1.text<Bob/bob-1/>")
-             (test-uniq-file-hilit '(0 8) "foo-file1.text<Bob/bob-2/>")
-             (test-uniq-file-hilit '(0 8) "foo-file2.text<Alice/alice-1/>")
-             (test-uniq-file-hilit '(0 8) "foo-file2.text<Bob/bob-1/>")
-             (test-uniq-file-hilit '(0 8) "foo-file3.text")
-             (test-uniq-file-hilit '(0 8) "foo-file3.texts")
-             (test-uniq-file-hilit '(0 8) "foo-file3.texts2")
-             (test-uniq-file-hilit '(0 8) "foo-file4.text<Alice/alice-3/>")
-             (test-uniq-file-hilit '(0 8) "foo-file4.text<Bob/alice-3/>")
-             (test-uniq-file-hilit '(0 8) "foo-file5.text")
-             )))
-
-    (should (equal-including-properties
             (sort (uniq-file-all-completions "b" table nil nil) #'string-lessp)
             (list
              (test-uniq-file-hilit '(8) "bar-file1.text<alice-1/>")
@@ -445,10 +332,20 @@ all positions in POS-LIST in STRING; return new string."
              (test-uniq-file-hilit '(14) "foo-file3.texts2")
              )))
 
+    ;; Two places for possible completion, with different intervening text
+    (should (equal-including-properties
+            (sort (uniq-file-all-completions "wisi-te" table nil 5) 
#'string-lessp)
+            (list                         ;; 0         10        20        30
+             (test-uniq-file-hilit '(10 18) 
"wisitoken-generate-packrat-test.text")
+             (test-uniq-file-hilit '(10 25) "wisitoken-syntax_trees-test.text")
+             (test-uniq-file-hilit '(10 12) "wisitoken-text_io_trace.text")
+             )))
     ))
 
-(defun test-uniq-file-try-completion-1 (table)
-  (let (string)
+(ert-deftest test-uniq-file-try-completion ()
+  (let ((table (uft-table))
+       (completion-ignore-case nil)
+        string)
 
     (setq string "fo")
     (should (equal (uniq-file-try-completion string table nil (length string))
@@ -460,14 +357,14 @@ all positions in POS-LIST in STRING; return new string."
 
     (setq string "fo<al")
     (should (equal (uniq-file-try-completion string table nil 2)
-                  '("foo-file<alice-" . 8)))
+                  '("foo-file.text<alice-" . 8)))
     (should (equal (uniq-file-try-completion string table nil 5)
                   '("foo-file<alice-" . 15)))
 
     (let ((completion-ignore-case t))
       (setq string "fo<al")
       (should (equal (uniq-file-try-completion string table nil 2)
-                    '("foo-file<alice" . 8)))
+                    '("foo-file.text<alice" . 8)))
       (should (equal (uniq-file-try-completion string table nil 5)
                     '("foo-file<alice" . 14)))
       )
@@ -494,16 +391,10 @@ all positions in POS-LIST in STRING; return new string."
     (should (equal (uniq-file-try-completion string table nil (length string))
                   (cons "foo-file1.text<>" 15)))
 
-    (setq string "foo-file1.text<alice-1/>") ;; valid and unique
+    (setq string "foo-file1.text<Alice/alice-1/>") ;; valid and unique
     (should (equal (uniq-file-try-completion string table nil (length string))
                   t))
 
-    (let ((completion-ignore-case t))
-      (setq string "foo-file1.text<alice-1/>") ;; valid and unique, but 
accidental match on Alice
-      (should (equal (uniq-file-try-completion string table nil (length 
string))
-                    '("foo-file1.text<Alice/alice-1/>" . 30)))
-      )
-
     (setq string "foo-file3.texts") ;; not unique, valid
     (should (equal (uniq-file-try-completion string table nil (length string))
                   '("foo-file3.texts" . 15)))
@@ -538,147 +429,58 @@ all positions in POS-LIST in STRING; return new string."
                     (cons "foo-file" 8))))
     ))
 
-(ert-deftest test-uniq-file-try-completion-func ()
-  (let ((table (apply-partially 'uniq-file-completion-table uft-iter))
-       (completion-current-style 'uniquify-file)
-       (completion-ignore-case nil))
-    (test-uniq-file-try-completion-1 table)))
-
-(ert-deftest test-uniq-file-try-completion-list ()
-  (let ((table (path-iter-all-files uft-iter))
-       (completion-ignore-case nil)
-       (completion-styles '(uniquify-file))) ;; FIXME: need a way to specify 
category
-    (test-uniq-file-try-completion-1 table)))
-
-(ert-deftest test-uniq-file-get-data-string ()
-  (let ((table (apply-partially 'uniq-file-completion-table uft-iter)))
-
-    (should (equal (uniq-file-get-data-string "foo-file1.text<alice-1>" table 
nil)
-                  (concat uft-alice1 "/foo-file1.text")))
-
-    (should (equal (uniq-file-get-data-string "foo-file3.text" table nil)
-                  (concat uft-alice2 "/foo-file3.text")))
-
-    (should (equal (uniq-file-get-data-string "foo-file3.texts" table nil)
-                  (concat uft-alice2 "/foo-file3.texts")))
-
-    (should (equal (uniq-file-get-data-string "foo-file3.texts2" table nil)
-                  (concat uft-root "/foo-file3.texts2")))
-    ))
-
-(ert-deftest test-uniq-file-to-table-input ()
-  (should (equal (uniq-file-to-table-input "fi" nil nil)
-                "fi"))
-
-  (should (equal (uniq-file-to-table-input "fi<di" nil nil)
-                "di/fi"))
-
-  (should (equal (uniq-file-to-table-input "foo-file1.text" nil nil)
-                "foo-file1.text"))
-
-  (should (equal (uniq-file-to-table-input "file1<Alice/alice-2/>" nil nil)
-                "Alice/alice-2/file1"))
-
-  (should (equal (uniq-file-to-table-input "file1<>" nil nil)
-                "file1"))
-
-  (should (equal (uniq-file-to-table-input "file1.text<Alice/alice-2/>" nil 
nil)
-                "Alice/alice-2/file1.text"))
-
-  (should (equal (uniq-file-to-table-input "bar-file2.text<Alice/alice-" nil 
nil)
-                "Alice/alice-/bar-file2.text"))
-
-  )
-
 (ert-deftest test-uniq-file-uniquify ()
-  (should (equal (uniq-file--uniquify
-                 '("/Alice/alice1/file1.text" "/Alice/alice1/file2.text"
-                   "/Alice/alice2/file1.text" "/Alice/alice2/file3.text"
-                   "/Bob/bob1/file1.text")
-                 nil)
-                (list "file1.text<Alice/alice1/>"
-                      "file1.text<Alice/alice2/>"
-                      "file1.text<Bob/bob1/>"
-                      "file2.text"
-                      "file3.text")))
-
-  (should (equal (uniq-file--uniquify '("/Alice/alice1/file1.text" 
"/Alice/alice2/file1.text") nil)
-                (list "file1.text<alice1/>" "file1.text<alice2/>")))
-
-  (should (equal (uniq-file--uniquify '("/alice1/file2.text") nil)
-                (list "file2.text")))
-
-  (should (equal (uniq-file--uniquify
-                 '("c:/tmp/test/alice-1/bar-file1.text"
-                   "c:/tmp/test/alice-1/bar-file2.text")
-                 "a-1")
-                (list "bar-file1.text<alice-1/>" "bar-file2.text<alice-1/>")))
-
-  (should (equal (uniq-file--uniquify
-                 '("c:/tmp/Alice/alice-1/bar-file1.text"
-                   "c:/tmp/Alice/alice-1/bar-file2.text"
-                   "c:/tmp/Alice/alice-2/bar-file2.text")
-                 "a-")
-
-                ;; FIXME: This result reflects a bug in
-                ;; `completion-pcm--pattern->regex'; "a-" becomes
-                ;; "a.*?-", but it should be (concat "a[^"
-                ;; wildcards "]*-".
-
-                (list "bar-file1.text<Alice/alice-1/>"
-                      "bar-file2.text<Alice/alice-1/>"
-                      "bar-file2.text<Alice/alice-2/>")))
-
-  (should (equal (uniq-file--uniquify
-                 '("c:/tmp/Alice/alice-1/bar-file1.text"
-                   "c:/tmp/Alice/alice-1/bar-file2.text"
-                   "c:/tmp/Alice/alice-2/bar-file2.text")
-                 "Al/a-")
-                (list "bar-file1.text<Alice/alice-1/>"
-                      "bar-file2.text<Alice/alice-1/>"
-                      "bar-file2.text<Alice/alice-2/>")))
-
-  ;; From "foo-file1.text<>"
-  (should (equal (uniq-file--uniquify
+  (should (equal (uniq-file-uniquify
+                 '("/Alice/alice1/file1.text"
+                    "/Alice/alice1/file2.text"
+                   "/Alice/alice2/file1.text"
+                    "/Alice/alice2/file3.text"
+                   "/Bob/bob1/file1.text"))
+                (list
+                 '("file3.text"                . "/Alice/alice2/file3.text")
+                 '("file2.text"                . "/Alice/alice1/file2.text")
+                 '("file1.text<Bob/bob1/>"     . "/Bob/bob1/file1.text")
+                 '("file1.text<Alice/alice2/>" . "/Alice/alice2/file1.text")
+                  '("file1.text<Alice/alice1/>" . "/Alice/alice1/file1.text")
+                  )))
+
+  (should (equal (uniq-file-uniquify
                  (list
                   (concat uft-alice1 "/foo-file1.text")
                   (concat uft-alice2 "/foo-file1.text")
                   (concat uft-bob1 "/foo-file1.text")
                   (concat uft-bob2 "/foo-file1.text")
                   (concat uft-root "/foo-file1.text")
-                  )
-                 "")
-                '(
-                  "foo-file1.text<Alice/alice-1/>"
-                  "foo-file1.text<Alice/alice-2/>"
-                  "foo-file1.text<Bob/bob-1/>"
-                  "foo-file1.text<Bob/bob-2/>"
-                  "foo-file1.text<>"
-                  )))
-
-  ;; from cedet-global-test
-  (should (equal (uniq-file--uniquify
+                  ))
+                (list
+                 (cons "foo-file1.text<>"               (concat uft-root 
"/foo-file1.text"))
+                 (cons "foo-file1.text<Bob/bob-2/>"     (concat uft-bob2 
"/foo-file1.text"))
+                  (cons "foo-file1.text<Bob/bob-1/>"     (concat uft-bob1 
"/foo-file1.text"))
+                  (cons "foo-file1.text<Alice/alice-2/>" (concat uft-alice2 
"/foo-file1.text"))
+                 (cons "foo-file1.text<Alice/alice-1/>" (concat uft-alice1 
"/foo-file1.text"))
+                  )))
+
+  (should (equal (uniq-file-uniquify
                  (list
                   (concat uft-alice1 "/bar-file1.c")
                   (concat uft-alice1 "/bar-file2.c")
                   (concat uft-alice2 "/bar-file1.c")
                   (concat uft-alice2 "/bar-file2.c")
-                  (concat uft-bob1 "/foo-file1.c") ;; 'b' in directory part; 
accidental match
+                  (concat uft-bob1 "/foo-file1.c")
                   (concat uft-bob1 "/foo-file2.c")
                   (concat uft-bob2 "/foo-file1.c")
                   (concat uft-bob2 "/foo-file5.c")
-                  )
-                 nil)
-                '(
-                  "bar-file1.c<alice-1/>"
-                  "bar-file1.c<alice-2/>"
-                  "bar-file2.c<alice-1/>"
-                  "bar-file2.c<alice-2/>"
-                  "foo-file1.c<bob-1/>"
-                  "foo-file1.c<bob-2/>"
-                  "foo-file2.c"
-                  "foo-file5.c"
-                  )))
+                  ))
+                (list
+                  (cons "foo-file5.c"           (concat uft-bob2 
"/foo-file5.c"))
+                 (cons "foo-file2.c"           (concat uft-bob1 
"/foo-file2.c"))
+                  (cons "foo-file1.c<bob-2/>"   (concat uft-bob2 
"/foo-file1.c"))
+                  (cons "foo-file1.c<bob-1/>"   (concat uft-bob1 
"/foo-file1.c"))
+                  (cons "bar-file2.c<alice-2/>" (concat uft-alice2 
"/bar-file2.c"))
+                  (cons "bar-file2.c<alice-1/>" (concat uft-alice1 
"/bar-file2.c"))
+                  (cons "bar-file1.c<alice-2/>" (concat uft-alice2 
"/bar-file1.c"))
+                  (cons "bar-file1.c<alice-1/>" (concat uft-alice1 
"/bar-file1.c"))
+                  )))
   )
 
 (provide 'uniquify-files-test)
diff --git a/packages/uniquify-files/uniquify-files.el 
b/packages/uniquify-files/uniquify-files.el
index 923e680..a74a450 100644
--- a/packages/uniquify-files/uniquify-files.el
+++ b/packages/uniquify-files/uniquify-files.el
@@ -1,6 +1,6 @@
-;;; uniquify-files.el --- Completion style for files in a path  -*- 
lexical-binding:t -*-
+4;;; uniquify-files.el --- Completion style for files, minimizing directories  
-*- lexical-binding:t -*-
 ;;
-;; Copyright (C) 2017, 2019  Free Software Foundation, Inc.
+;; Copyright (C) 2019  Free Software Foundation, Inc.
 ;;
 ;; Author: Stephen Leake <stephen_le...@stephe-leake.org>
 ;; Maintainer: Stephen Leake <stephen_le...@stephe-leake.org>
@@ -24,161 +24,18 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
+;;; Commentary
 
-;;; Discussion
-;;;
-;; These are the driving requirements for this completion style:
-;;
-;; 1. Allow the strings entered by the user and displayed in the
-;;    completion list to be rearranged abbreviations of the absolute
-;;    file name returned by `completing-read'.
-;;
-;; 2. Allow partial completion on the directory and filename portions
-;;    of the abbreviated strings.
-;;
-;;    "partial completion" means file names are partitioned at "_-/"
-;;    characters, so "fo-ba" completes to "foo-bar".
-;;
-;; 3. The style should be usable with the completion table function
-;;    provided here, or with a list of absolute file names.
-
-;; Requirement 1 has the most effect on the design. There are two
-;; common ways to select the result of a completion:
-;;
-;; - `minibuffer-complete-and-exit' - by default bound to <ret> in the
-;;   minibuffer when `icomplete-mode' is enabled.
-;;
-;; - `minibuffer-force-complete-and-exit' - some users bind this to
-;;    <ret> or other keys, so that it is easier to select the first
-;;    completion.
-;;
-;; One possible design is to have `completion-try-completion' return
-;; an absolute file name (rather than an abbreviated file name) when
-;; the completed string is a valid completion. That sometimes works
-;; with `minibuffer-complete-and-exit', but it does not work with
-;; `minibuffer-force-complete-and-exit'; details follow.
-
-;; The nominal path thru `minibuffer-complete-and-exit' in effect
-;; calls `test-completion'. If that returns nil, it calls
-;; `completion-try-completion' with the same string, and then
-;; `test-completion' on that result. If that returns non-nil, the
-;; completed string is returned as the result of
-;; `completing-read'. Thus `test-completion' could return nil for user
-;; format strings, and t for data format strings; and `try-completion'
-;; could convert user format strings that are valid completions to data
-;; format strings. However, the full logic is complex (see the code in
-;; minibuffer.el for more details), and often ends up not converting
-;; the user string to a data string.
-;;
-;; `minibuffer-force-complete-and-exit' calls
-;; `minibuffer-force-complete', which replaces the buffer text with
-;; the first completion. Then it calls `test-completion', but _not_
-;; `try-completion' if that fails. So there is no opportunity to
-;; convert the user string to a data string.
-;;
-;; Thus the design we use here adds an explicit conversion from user
-;; to data format, via advice on completing-read.
-;;
-;; We did not meet the third requirement; the completion table
-;; implements part of the completion style.
-
-;;; Design
-;;
-;; There are three string formats involved in completion. For most
-;; styles, they are all the same; the following table describes them
-;; for the uniquify-file style.
-;;
-;; - user
-;;
-;;   The format typed by the user in the minibuffer, and shown in the
-;;   displayed completion list.
-;;
-;;   The user input is passed to `completion-try-completion', so it must
-;;   accept this format.
-;;
-;;   The string returned by `completion-try-completion' when it extends
-;;   the string replaces the string typed by the user, so it must be
-;;   in this format.
-;;
-;;   The text displayed by `completing-read' consists of the current
-;;   input string followed by a completion list.  The completion list
-;;   consists of the strings returned by `completion-all-completions'
-;;   with the common prefix deleted (the common prefix is in the
-;;   completion string); `completion-all-completions' must return
-;;   strings in this format.
-;;
-;;   When the user selects a displayed completion, the string is
-;;   passed to `test-completion'; it must accept strings in this format
-;;   and return t.
-;;
-;;   For the uniquify-file style, this is a partial or complete file
-;;   base name with any required uniquifying directories appended.
-;;
-;; - completion table input
-;;
-;;   The string input to the completion table function, or, if the
-;;   table is a list of absolute filenames, the string matched against
-;;   the table.
-;;
-;;   The `completion-try-completion' and `completion-all-completion'
-;;   `test-completion' functions must convert user format strings to
-;;   completion table input format strings when calling the
-;;   corresponding low-level completion functions that call the
-;;   completion table function.
-;;
-;;   For the uniquify-file style, this contains the complete or
-;;   partial directory name or no directory name, followed by the
-;;   partial or complete file base name, in normal elisp filename
-;;   format.
-;;
-;;   A completion table input string is a valid completion if the
-;;   string equals (respecting `completion-ignore-case') the tail of
-;;   an existing file name, starting after a directory separator and
-;;   ending at the end of the file name.
-;;
-;; - data
-;;
-;;   The string format desired as the result of `completing-read'.
-;;
-;;   In order to keep style-dependent code out of the completion table
-;;   function, the completion table function returns a list of strings
-;;   in this format when action is t; `completion-all-completions'
-;;   converts them to user format strings.
-;;
-;;   For the uniquify-file style, this is an absolute file name.
-;;
-;;
-;; As of Emacs 25.1, `completion-try-completion' and
-;; `completion-all-completion' support style-specific implementations
-;; via `completion-style-alist', but `test-completion' does not. So we
-;; advise `test-completion' to convert to the appropriate format first.
-;;
-;; Similarly, the current completion code does not have a provision
-;; for converting from user format to data format after a completion
-;; is selected; we add that via advice on `completing-read-default'. A
-;; future version may add this conversion in
-;; `completion--complete-and-exit' instead.
-;;
-;; In order to allow other completion styles that have different user
-;; and data string formats, we extend `completion-styles-alist' with
-;; two entries:
-;;
-;; - fourth entry contains a function that takes one argument
-;; USER-STRING and returns a table input format string. This is used
-;; by `completion-to-table-input' - advice for `test-completion'.
-;;
-;; - fifth entry contains a function that takes three arguments
-;; USER-STRING, TABLE, PREDICATE, and returns a list of data string
-;; format strings matching USER-STRING. This is used by
-;; `completion-get-data-string'.
+;; A file completion style in which the completion string displayed to
+;; the user consists of the file basename followed by enough of the
+;; directory part to make the string identify a unique file.
 ;;
+;; We accomplish this by preprocessing the list of absolute file names
+;; to be in that style, in an alist with the original absolute file
+;; names, and do completion on that alist.
 
 (require 'cl-lib)
-(require 'file-complete)
-(require 'path-iterator)
-
-(defvar completion-current-style nil
-  "Current active completion style.")
+(require 'files)
 
 (defconst uniq-file--regexp "^\\(.*\\)<\\([^>]*\\)>?$"
   ;; The trailing '>' is optional so the user can type "<dir" in the
@@ -186,37 +43,7 @@
   "Regexp matching uniqufied file name.
 Match 1 is the filename, match 2 is the relative directory.")
 
-(defun uniq-file--dir-match (partial abs)
-  "Return the portion of ABS that matches PARTIAL; both are directories."
-  (cond
-   ((and partial
-        (< 0 (length partial)))
-    (let* ((pattern (completion-pcm--string->pattern partial nil))
-          (regex (completion-pcm--pattern->regex pattern)))
-
-      ;; `regex' is anchored at the beginning; delete the anchor to
-      ;; match a directory in the middle of ABS.
-      (setq regex (substring regex 2))
-
-      ;; Include the preceding and following '/' .
-      (unless (= ?/ (aref regex 0))
-       (setq regex (concat "/" regex)))
-      (unless (= ?/ (aref regex (1- (length regex))))
-       (setq regex (concat regex "[^/]*/" )))
-
-      (when (string-match regex abs);; Should never fail, but gives obscure 
error if it does
-
-       ;; Drop the leading '/', include all trailing directories;
-       ;; consider Bob/alice-3/foo, Alice/alice-3/foo.
-       (substring abs (1+ (match-beginning 0))))
-      ))
-
-   (t
-    ;; no partial; nothing matches
-    "")
-   ))
-
-(defun uniq-file--conflicts (conflicts dir)
+(defun uniq-file-conflicts (conflicts)
   "Subroutine of `uniq-file-uniquify'."
   (let ((common-root ;; shared prefix of dirs in conflicts - may be nil
         (fill-common-string-prefix (file-name-directory (nth 0 conflicts)) 
(file-name-directory (nth 1 conflicts)))))
@@ -236,125 +63,47 @@ Match 1 is the filename, match 2 is the relative 
directory.")
 
     (cl-mapcar
      (lambda (name)
-       ;; The set of `non-common' is unique, but we also need to
-       ;; include all of `completed-dir' in the result.
-       ;;
-       ;; examples
-       ;;   1. uniquify-files-test.el test-uniq-file-uniquify, dir "Al/a-"
-       ;;      conflicts:
-       ;;         .../Alice/alice-1/bar-file1.text
-       ;;         .../Alice/alice-1/bar-file2.text
-       ;;         .../Alice/alice-2/bar-file2.text
-       ;;      common        : .../Alice/
-       ;;      non-common    : alice-1/, alice-2/
-       ;;      completed-dir : Alice/alice-1/, Alice/alice-2/
-       ;;
-       ;;   2. uniquify-files-test.el test-uniq-file-all-completions-noface-1 
"f-file4.text<a-3"
-       ;;      conflicts:
-       ;;         .../uniquify-files-resources/Alice/alice-3/foo-file4.text
-       ;;         .../uniquify-files-resources/Bob/alice-3/foo-file4.text
-       ;;      common        : .../uniquify-files-resources
-       ;;      non-common    : Alice/alice-3/, Bob/alice-3/
-       ;;      completed-dir : alice-3/
-       ;;
-       (let ((completed-dir (and dir (uniq-file--dir-match dir 
(file-name-directory name))))
-            (non-common (substring (file-name-directory name) (length 
common-root))))
-
-        (when (and completed-dir
-                   (not (string-match completed-dir non-common)))
-          ;; case 1.
-          (let* ((completed-dirs (and completed-dir (nreverse (split-string 
completed-dir "/" t))))
-                 (first-non-common (substring non-common 0 (string-match "/" 
non-common))))
-            (while completed-dirs
-              (let ((dir1 (pop completed-dirs)))
-                (when (not (string-equal dir1 first-non-common))
-                  (setq non-common (concat dir1 "/" non-common)))))))
-        ;; else case 2; non-common is correct
-
-        (concat (file-name-nondirectory name) "<" non-common ">")
-        ))
+        (cons (concat (file-name-nondirectory name)
+                       "<"
+                       (substring (file-name-directory name) (length 
common-root))
+                       ">")
+               name))
      conflicts)
     ))
 
-(defun uniq-file--uniquify (names dir)
-  "Return a uniquified list of names built from NAMES.
-NAMES contains absolute file names.
-
-The result contains non-directory filenames with partial
-directory paths appended.  The partial directory path will always
-include at least the completion of DIR.
-
-If DIR is non-nil, all elements of NAMES must match DIR."
-  ;;  AKA uniq-file-to-user; convert list of data format strings to list of 
user format strings.
-  (let ((case-fold-search completion-ignore-case))
-    (when names
-      (let (result
-           conflicts ;; list of names where all non-directory names are the 
same.
-           )
-
-       ;; Sort names on basename so duplicates are grouped together
-       (setq names (sort names (lambda (a b)
-                                 (string< (file-name-nondirectory a) 
(file-name-nondirectory b)))))
-
-       (while names
-         (setq conflicts (list (pop names)))
-         (while (and names
-                     (string= (file-name-nondirectory (car conflicts)) 
(file-name-nondirectory (car names))))
-           (push (pop names) conflicts))
-
-         (if (= 1 (length conflicts))
-             (let ((completed-dir (and dir (uniq-file--dir-match dir 
(file-name-directory (car conflicts))))))
-               (push
-                (if completed-dir
-                    (concat (file-name-nondirectory (car conflicts)) "<" 
completed-dir ">")
-
-                  (concat (file-name-nondirectory (car conflicts))))
-                result))
-
-           (setq result (append (uniq-file--conflicts conflicts dir) result)))
-         )
-       (nreverse result)
-       ))
-    ))
-
-(defun uniq-file-to-table-input (user-string _table _pred)
-  "Implement `completion-to-table-input' for uniquify-file."
-  (let* ((match (string-match uniq-file--regexp user-string))
-        (dir (and match (match-string 2 user-string))))
-
-    (if match
-       (if (= 0 (length dir)) ;; ie "file<"
-           (match-string 1 user-string)
-         (concat (file-name-as-directory dir) (match-string 1 user-string)))
-
-      ;; else not uniquified
-      user-string)))
-
-(defun uniq-file--valid-regexp (string)
-  "Return a regexp matching STRING (in table input format) to an absolute file 
name.
-Regexp matches if the file name is a valid completion."
-  (concat (unless (file-name-absolute-p string) "/") string "\\'"))
-
-(defun uniq-file--valid-completion (string all)
-  "Return non-nil if STRING is a valid completion in ALL,
-else return nil.  ALL should be the result of `all-completions'.
-STRING should be in completion table input format."
-  ;; STRING is a valid completion if it is a tail of at least one
-  ;; element of ALL, including at least the base name.
-  (let* ((regexp (uniq-file--valid-regexp string))
-        (matched nil)
-        name)
-
-    (while (and all
-               (not matched))
-      (setq name (pop all))
-      (when (string-match regexp name)
-       (setq matched t)))
-
-    matched))
+(defun uniq-file-uniquify (names)
+  "Return an alist of uniquified names built from NAMES.
+NAMES is a list containing absolute file names.
+
+The result contains file basenames with partial directory paths
+appended."
+  (let ((case-fold-search completion-ignore-case)
+        result
+       conflicts ;; list of names where all non-directory names are the same.
+       )
+
+    ;; Sort names on basename so duplicates are grouped together
+    (setq names (sort names (lambda (a b)
+                             (string< (file-name-nondirectory a) 
(file-name-nondirectory b)))))
+
+    (while names
+      (setq conflicts (list (pop names)))
+      (while (and names
+                 (string= (file-name-nondirectory (car conflicts)) 
(file-name-nondirectory (car names))))
+       (push (pop names) conflicts))
+
+      (if (= 1 (length conflicts))
+         (push (cons
+                (concat (file-name-nondirectory (car conflicts)))
+                (car conflicts))
+               result)
+
+        (setq result (append (uniq-file-conflicts conflicts) result)))
+      )
+    result))
 
 (defun uniq-file--pcm-pat (string point)
-  "Return a pcm pattern that matches STRING (a user format string)."
+  "Return a pcm pattern that matches STRING (a uniquified file name)."
   (let* ((completion-pcm--delim-wild-regex
          (concat "[" completion-pcm-word-delimiters "<>*]"))
         ;; If STRING ends in an empty directory part, some valid
@@ -386,27 +135,20 @@ STRING should be in completion table input format."
 
 (defun uniq-file--pcm-merged-pat (string all point)
   "Return a pcm pattern that is the merged completion of STRING in ALL.
-ALL must be a list of user format strings.
+ALL must be a list of uniquified file names.
 Pattern is in reverse order."
   (let* ((pattern (uniq-file--pcm-pat string point)))
     (completion-pcm--merge-completions all pattern)))
 
 (defun uniq-file-try-completion (user-string table pred point)
   "Implement `completion-try-completion' for uniquify-file."
-  ;; Returns common leading substring of completions of USER-STRING in table,
-  ;; consed with new point (length of common substring).
   (let (result
        uniq-all
        done)
 
-    (setq completion-current-style 'uniquify-file)
-
     ;; Compute result or uniq-all, set done.
     (cond
-     ((or
-       (functionp table) ;; TABLE is a wrapper function that calls 
uniq-file-completion-table.
-       (and (consp table)
-           (file-name-absolute-p (car table)))) ;; TABLE is the original list 
of absolute file names.
+     ((functionp table) ;; TABLE is a wrapper function that calls 
uniq-file-completion-table.
 
       (setq uniq-all (uniq-file-all-completions user-string table pred point))
 
@@ -486,6 +228,9 @@ character after each completion field."
 
     (mapcar
      (lambda (str)
+       ;; First remove previously applied face; `str' may be a reference
+       ;; to a list used in a previous completion.
+       (remove-text-properties 0 (length str) '(face 
completions-first-difference) str)
        (when (string-match regex str)
         (cl-loop
          for i from 1 to field-count
@@ -498,204 +243,81 @@ character after each completion field."
        str)
      all)))
 
-(defun uniq-file--match-list (regexp-list file-name)
-  "Return non-nil if FILE-NAME matches all regular expressions in REGEXP-LIST,
-nil otherwise."
-  (let ((result t))
-    (dolist (regexp regexp-list)
-      (unless (string-match regexp file-name)
-       (setq result nil)))
-    result))
-
-(defun uniq-file-all-completions (user-string table pred point)
+(defun uniq-file-all-completions (string table pred point)
   "Implement `completion-all-completions' for uniquify-file."
   ;; Returns list of data format strings (abs file names).
-
-  (let ((table-string (uniq-file-to-table-input user-string table pred))
-       all)
-
-    (setq completion-current-style 'uniquify-file)
-
-    (cond
-     ((functionp table)
-      (setq all (funcall table table-string pred t)))
-
-     ((and (consp table)
-          (file-name-absolute-p (car table)))
-      ;; TABLE is a list of absolute file names.
-
-      (pcase-let ((`(,dir-regex ,file-regex)
-                  (file-complete--iter-pcm-regex table-string 'basename nil)))
-       (let ((completion-regexp-list (cons file-regex completion-regexp-list))
-             (case-fold-search completion-ignore-case))
-         (dolist (file-name table)
-           (when (and
-                  (string-match dir-regex (directory-file-name file-name))
-                  (uniq-file--match-list completion-regexp-list 
(file-name-nondirectory file-name))
-                  (or (null pred)
-                      (funcall pred file-name)))
-             (push file-name all)))
-         )))
-     )
-
+  (let ((all (all-completions string table pred)))
     (when all
-      (setq all (uniq-file--uniquify all (file-name-directory table-string)))
+      (uniq-file--hilit string all point))
+    ))
 
-      ;; Filter accidental matches; see uniquify-files-test.el
-      ;; test-uniq-file-try-completion-1 "f-file1.text<a-1"
-      (let ((regex1 (completion-pcm--pattern->regex (uniq-file--pcm-pat 
user-string point))))
-       (setq all (cl-delete-if-not (lambda (name) (string-match regex1 name)) 
all)))
+(defun uniq-file-completion-table (files string pred action)
+  "Implement a completion table for uniquified file names in FILES.
+FILES is an alist of (UNIQIFIED-NAME . ABS-NAME).  Completion is
+done on UNIQIFIED-NAME, PRED is called with ABS-NAME."
+  (cond
+   ((eq action 'alist)
+    (cdr (assoc string files #'string-equal)))
 
-      (setq all (uniq-file--hilit user-string all point))
-      all
-      )
-    ))
+   ((eq (car-safe action) 'boundaries)
+    ;; We don't use boundaries; return the default definition.
+    (cons 'boundaries
+         (cons 0 (length (cdr action)))))
 
-(defun uniq-file-get-data-string (user-string table pred)
-  "Implement `completion-get-data-string' for 'uniqify-file."
-  ;; We assume USER-STRING is complete, but it may not be unique, in
-  ;; both the file name and the directory; shortest completion of each
-  ;; portion is the correct one.
-  (let ((table-string (uniq-file-to-table-input user-string table pred))
-        all)
-    (cond
-     ((functionp table)
-      (setq all (all-completions table-string table pred)))
-
-     (t
-      ;; TABLE is list of absolute file names. Match table-string
-      ;; against tail of table entry.
-      (let ((regexp (uniq-file--valid-regexp table-string)))
-       (dolist (entry table)
-         (when (string-match regexp entry)
-           (push entry all)))
-       ))
-     )
+   ((eq action 'metadata)
+    (cons 'metadata
+         (list
+           ;; category controls what completion styles are appropriate.
+          '(category . uniquify-file)
+          )))
 
-    (setq
-     all
-     (sort all
-          (lambda (a b)
-            (let ((lfa (length (file-name-nondirectory a)))
-                  (lfb (length (file-name-nondirectory b))))
-              (if (= lfa lfb)
-                  (< (length a) (length b))
-                (< lfa lfb))
-              ))
-          ))
-
-    (or (car all)
-        "");; must return a string, not nil.
-    ))
+   ((memq action
+         '(nil    ;; Called from `try-completion'
+           lambda ;; Called from `test-completion'
+           t))    ;; Called from all-completions
+
+    (let ((regex (completion-pcm--pattern->regex
+                  (uniq-file--pcm-pat string (length string))))
+         (case-fold-search completion-ignore-case)
+         (result nil))
+      (dolist (pair files)
+       (when (and
+              (string-match regex (car pair))
+              (or (null pred)
+                  (funcall pred (cdr pair))))
+         (push (car pair) result)))
 
-;; FIXME: move to file-complete
-(defun completion-get-data-string (user-string table pred)
-  "Return the data string corresponding to USER-STRING."
-  (let* ((to-data-func (when completion-current-style (nth 5 (assq 
completion-current-style completion-styles-alist)))))
-    (if to-data-func
-       (funcall to-data-func user-string table pred)
-      user-string))
-  )
-
-(defun completion-to-table-input (orig-fun user-string table &optional pred)
-  "Convert user string to table input."
-  (let* ((table-string
-         (let ((to-table-func (if (functionp table)
-                                  (nth 4 (assq completion-current-style 
completion-styles-alist)) ;; user to table
-
-                                ;; TABLE is a list of absolute file names
-                                (nth 5 (assq completion-current-style 
completion-styles-alist)) ;; user to data
-                                )))
-           (if to-table-func
-               (funcall to-table-func user-string table pred)
-             user-string))))
-    (funcall orig-fun table-string table pred)
-    )
-  )
-
-(advice-add #'test-completion :around #'completion-to-table-input)
-
-(defun uniq-file-completing-read-default-advice (orig-fun prompt collection 
&optional predicate
-                                                         require-match 
initial-input hist def
-                                                         inherit-input-method)
-  "Advice for `completing-read-default'; convert user string to data string."
-  (let* ((completion-current-style nil)
-        (user-string (funcall orig-fun prompt collection
-                             predicate require-match initial-input hist def
-                             inherit-input-method)))
-
-    (unless completion-current-style
-      ;; If completion-current-style is not set here, it's because the
-      ;; user invoked `exit-minibuffer' to use the default string, or
-      ;; because the completion functions did not set it (they are
-      ;; legacy).
-      (setq completion-current-style (car (cdr (assq 'styles 
(completion-metadata "" collection nil))))))
-    (completion-get-data-string user-string collection predicate)
-    ))
+      (cond
+       ((null action)
+       (try-completion string result))
 
-(advice-add #'completing-read-default :around 
#'uniq-file-completing-read-default-advice)
+       ((eq 'lambda action)
+       (test-completion string files pred))
+
+       ((eq t action)
+       result)
+       )))
+   ))
 
 (add-to-list 'completion-styles-alist
             '(uniquify-file
               uniq-file-try-completion
               uniq-file-all-completions
-              "display uniquified filenames."
-              uniq-file-to-table-input    ;; 4 user to table input format
-              uniq-file-get-data-string)) ;; 5 user to data format
+              "display uniquified file names."))
 
-(defun uniq-file-completion-table (path-iter string pred action)
-  "Implement a completion table for file names in PATH-ITER."
+;;; Integration with project.el
 
-  ;; We just add `styles' metadata to `path-iter-completion-table'.
-  (cond
-   ((eq action 'metadata)
-    (cons 'metadata
-         (list
-          '(category . project-file)
-          '(styles . (uniquify-file))
-          )))
+;;;###autoload
+(defun uniq-file-read (prompt all-files &optional predicate hist default)
+  "For `project-read-file-name-function'."
+  (let* ((alist (uniq-file-uniquify all-files))
+         (table (apply-partially #'uniq-file-completion-table alist))
+         (found (project--completing-read-strict
+                 prompt table predicate hist default)))
+    (cdr (assoc found alist))))
 
-   (t
-    (file-complete-completion-table path-iter 'basename nil string pred 
action))
-   ))
-
-(defun locate-uniquified-file (&optional path predicate default prompt)
-  "Return an absolute filename, with completion in non-recursive PATH
-\(default `load-path').  If PREDICATE is nil, it is ignored. If
-non-nil, it must be a function that takes one argument; the
-absolute file name.  The file name is included in the result if
-PRED returns non-nil. DEFAULT is the default for completion.
-
-In the user input string, `*' is treated as a wildcard."
-  (interactive)
-  (let* ((iter (make-path-iterator :user-path-non-recursive (or path 
load-path)))
-        (table (apply-partially #'uniq-file-completion-table iter))
-        (table-styles (cdr (assq 'styles (completion-metadata "" table nil))))
-        (completion-category-overrides
-         (list (list 'project-file (cons 'styles table-styles)))))
-    (completing-read (or prompt "file: ")
-                    table
-                    predicate t nil nil default)
-    ))
-
-(defun locate-uniquified-file-iter (iter &optional predicate default prompt)
-  "Return an absolute filename, with uniquify-file completion style.
-ITER is a path-iterator giving the directory path to search.
-If PREDICATE is nil, it is ignored. If non-nil, it must be a
-function that takes one argument; the absolute file name.  The
-file name is included in the result if PRED returns
-non-nil. DEFAULT is the default for completion.
-
-In the user input string, `*' is treated as a wildcard."
-  (let* ((table (apply-partially #'uniq-file-completion-table iter))
-        (table-styles (cdr (assq 'styles (completion-metadata "" table nil))))
-        (completion-category-overrides
-         (list (list 'project-file (cons 'styles table-styles)))))
-
-    (completing-read (format (concat (or prompt "file") " (%s): ") default)
-                    table
-                    predicate t nil nil default)
-    ))
+;;;###autoload
+(setq-default project-read-file-name-function #'uniq-file-read)
 
 (provide 'uniquify-files)
 ;;; uniquify-files.el ends here

Reply via email to