diff --git a/evil-commands.el b/evil-commands.el index 4ad249fc..9532a381 100644 --- a/evil-commands.el +++ b/evil-commands.el @@ -3349,6 +3349,14 @@ If no FILE is specified, reload the current buffer from disk as read-only." (revert-buffer bang (or bang (not (buffer-modified-p))) t) (read-only-mode +1))) +(evil-define-command evil-buffer-add (file) + "Add FILE to the buffer list, but don't visit it. " + :repeat nil + (interactive "") + (if (or (not file) (string= "" file)) + (user-error "No file specified") + (find-file-noselect file))) + (evil-define-command evil-read (count file) "Insert the contents of FILE below the current line or line COUNT." :repeat nil @@ -3727,6 +3735,43 @@ Supports positions in the following formats: \"path:line path(line)\", (when column-number (move-to-column (1- column-number))))))) +(evil-define-command evil-goto-file (file-path) + "Open the file under cursor and go to position if present. +Supports both relative path and absolute path. If path is relative, then find common +ancestor of path and current buffer file. If path is absolute path, go to the file +directly. Otherwise, fallback to `find-file-at-point`. + +Please notice that for relative path under cursor, only the most possible searching +approach is implemented in this version. There are many possible relative filepath +searching approaches, for example, same directory of current buffer, project root, +paths in system path environment. The most possible search approach would be the +same ancestor directory of current buffer and the target path, from parent directory +to root directory. +" + (interactive + (list (thing-at-point 'filename t))) + + (if (file-name-absolute-p file-path) + (find-file file-path) + + (let* ((delimiter (if (eq system-type 'windows-nt) + "\\" + "/")) + (parts (split-string (buffer-file-name) delimiter)) + (target-filename "") + (target-exists)) + + ;; check every combination of sub directory and file-path + (dolist (n (number-sequence (length parts) 1 -1) target-filename) + (let* ((new-filename (string-join (append (take n parts) (list file-path)) delimiter))) + (if (file-exists-p new-filename) + (setq target-filename new-filename + target-exists t)))) + + (if target-exists + (find-file target-filename) + (find-file-at-point file-path))))) + (evil-define-command evil-find-file-at-point-visual () "Find the filename selected by the visual region. Signal an error if the file does not exist." diff --git a/evil-maps.el b/evil-maps.el index 0dfa85dd..7a74fa68 100644 --- a/evil-maps.el +++ b/evil-maps.el @@ -75,9 +75,9 @@ (define-key evil-normal-state-map "gw" 'evil-fill) (define-key evil-normal-state-map "gu" 'evil-downcase) (define-key evil-normal-state-map "gU" 'evil-upcase) -(define-key evil-normal-state-map "gf" 'find-file-at-point) -(define-key evil-normal-state-map "]f" 'find-file-at-point) -(define-key evil-normal-state-map "[f" 'find-file-at-point) +(define-key evil-normal-state-map "gf" 'evil-goto-file) +(define-key evil-normal-state-map "]f" 'evil-goto-file) +(define-key evil-normal-state-map "[f" 'evil-goto-file) (define-key evil-normal-state-map "gF" 'evil-find-file-at-point-with-line) (define-key evil-normal-state-map "]F" 'evil-find-file-at-point-with-line) (define-key evil-normal-state-map "[F" 'evil-find-file-at-point-with-line) @@ -515,6 +515,7 @@ included in `evil-insert-state-bindings' by default." (evil-ex-define-cmd "sav[eas]" 'evil-save) (evil-ex-define-cmd "r[ead]" 'evil-read) (evil-ex-define-cmd "b[uffer]" 'evil-buffer) +(evil-ex-define-cmd "bad[d]" 'evil-buffer-add) (evil-ex-define-cmd "bn[ext]" 'evil-next-buffer) (evil-ex-define-cmd "bp[revious]" 'evil-prev-buffer) (evil-ex-define-cmd "bN[ext]" "bprevious")