X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/dc7d01f89b664abcbdf482b9db6e5e8a1a369e04..4a6eea94edb138a3ea73e7a50553b69dedc5c3ad:/company-files.el diff --git a/company-files.el b/company-files.el index 6c0775c2b..53730c6e0 100644 --- a/company-files.el +++ b/company-files.el @@ -1,80 +1,111 @@ -;;; company-files.el --- a company-mode completion back-end for file names -;; -;; Copyright (C) 2009 Nikolaj Schumacher -;; -;; This file is part of company 0.5. -;; -;; This program 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 2 -;; of the License, or (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, +;;; company-files.el --- company-mode completion backend for file paths + +;; Copyright (C) 2009-2011, 2014-2015 Free Software Foundation, Inc. + +;; Author: Nikolaj Schumacher + +;; 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 this program. If not, see . +;; along with GNU Emacs. If not, see . + + +;;; Commentary: +;; + +;;; Code: (require 'company) -(eval-when-compile (require 'cl)) +(require 'cl-lib) -(defun company-files-directory-files (dir prefix) +(defun company-files--directory-files (dir prefix) (ignore-errors (if (equal prefix "") (directory-files dir nil "\\`[^.]\\|\\`.[^.]") (file-name-all-completions prefix dir)))) -(defvar company-files-regexps - (let ((begin (if (eq system-type 'windows-nt) - "[a-z][A-Z]\\" - "~?/"))) +(defvar company-files--regexps + (let* ((root (if (eq system-type 'windows-nt) + "[a-zA-Z]:/" + "/")) + (begin (concat "\\(?:\\.\\{1,2\\}/\\|~/\\|" root "\\)"))) (list (concat "\"\\(" begin "[^\"\n]*\\)") (concat "\'\\(" begin "[^\'\n]*\\)") (concat "\\(?:[ \t]\\|^\\)\\(" begin "[^ \t\n]*\\)")))) -(defun company-files-grab-existing-name () - ;; Grab file names with spaces, only when they include quotes. +(defun company-files--grab-existing-name () + ;; Grab the file name. + ;; When surrounded with quotes, it can include spaces. (let (file dir) - (and (dolist (regexp company-files-regexps) + (and (cl-dolist (regexp company-files--regexps) (when (setq file (company-grab-line regexp 1)) - (return file))) + (cl-return file))) + (company-files--connected-p file) (setq dir (file-name-directory file)) (not (string-match "//" dir)) (file-exists-p dir) (file-name-all-completions (file-name-nondirectory file) dir) file))) -(defvar company-files-completion-cache nil) +(defun company-files--connected-p (file) + (or (not (file-remote-p file)) + (file-remote-p file nil t))) -(defun company-files-complete (prefix) +(defvar company-files--completion-cache nil) + +(defun company-files--complete (prefix) (let* ((dir (file-name-directory prefix)) + (key (list (file-name-nondirectory prefix) + (expand-file-name dir) + (nth 5 (file-attributes dir)))) (file (file-name-nondirectory prefix)) - candidates) - (unless (equal dir (car company-files-completion-cache)) - (dolist (file (company-files-directory-files dir file)) + (completion-ignore-case read-file-name-completion-ignore-case) + candidates directories) + (unless (company-file--keys-match-p key (car company-files--completion-cache)) + (dolist (file (company-files--directory-files dir file)) (setq file (concat dir file)) - (push file candidates) - (when (file-directory-p file) - ;; Add one level of children. - (dolist (child (company-files-directory-files file "")) - (push (concat file child) candidates)))) - (setq company-files-completion-cache (cons dir (nreverse candidates)))) - (cdr company-files-completion-cache))) + (when (company-files--connected-p file) + (push file candidates) + (when (file-directory-p file) + (push file directories)))) + (dolist (directory (reverse directories)) + ;; Add one level of children. + (dolist (child (company-files--directory-files directory "")) + (push (concat directory + (unless (eq (aref directory (1- (length directory))) ?/) "/") + child) candidates))) + (setq company-files--completion-cache (cons key (nreverse candidates)))) + (all-completions prefix + (cdr company-files--completion-cache)))) + +(defun company-file--keys-match-p (new old) + (and (equal (cdr old) (cdr new)) + (string-prefix-p (car old) (car new)))) ;;;###autoload (defun company-files (command &optional arg &rest ignored) - "a `company-mode' completion back-end existing file names." + "`company-mode' completion backend existing file names. +Completions works for proper absolute and relative files paths. +File paths with spaces are only supported inside strings." (interactive (list 'interactive)) - (case command - ('interactive (company-begin-backend 'company-files)) - ('prefix (company-files-grab-existing-name)) - ('candidates (company-files-complete arg)) - ('location (cons (dired-noselect - (file-name-directory (directory-file-name arg))) 1)) - ('sorted t) - ('no-cache t))) + (cl-case command + (interactive (company-begin-backend 'company-files)) + (prefix (company-files--grab-existing-name)) + (candidates (company-files--complete arg)) + (location (cons (dired-noselect + (file-name-directory (directory-file-name arg))) 1)) + (sorted t) + (no-cache t))) (provide 'company-files) ;;; company-files.el ends here