I want ff-find-other-file with specific functionality. I want it to be able to detect different related C++ headers for example. I also want it to ask if I want to create certain files. For example, I could have a project with a header “foo.hpp”. I would want it to ask me if I wanted to make “foo.cpp” on command if it doesn’t exist. But I would also want it to be able to make “fwd/foo.hpp” or “foo_fwd.hpp”. I don’t know if the ff-find-other-file supports this.
I was unaware of this package, the ff functions. I’ve been using a custom function for locating related files. The cool aspect of the package seems to be that it can find header files in many different directories.
I looked at the package and I could not find functions for programmatic use, but this seems to work.
(defun my/ff-find-other-file ()
(interactive)
(let ((ff-always-try-to-create nil ))
(unless (ff-get-other-file)
(when (yes-or-no-p "Create?: ")
(let ((ff-always-try-to-create t))
(ff-get-other-file))))))
2 Likes
Thanks. That is helpful. But I would like more complex patterns / the ability to have more then two related files.
I’ll post my current approach. I used to have two functions (goto-primary file and a goto-secondary-file) but I changed that to a rotate between the files approach. I haven’t refactored the code.
(setq primary-ext-table
#s(hash-table size 20 data (
;; Org
"\\.org$" (".org_archive" ".bib")
"\\.org_archive$" (".org")
"\\.bib$" (".org")
;; Angular
"\\.module.ts$" (".model.ts" ".component.ts")
"\\.component.ts$" (".model.ts" ".html")
"\\.component.html$" (".component.scss" ".ts")
"\\.component.scss$" (".component.html" ".ts")
;; txt|pdf
"\\.txt$" (".pdf")
"\\.pdf$" (".txt")
;; C/C++
"\\.c$\\|\\.cpp$" (".hpp" ".h")
"\\.hpp$" (".c" ".cpp")
"\\.h$" (".c" ".cpp")
;; Fractal
"\\.hbs$\\|\\.mustache$\\|\\.twig$\\|\\.nunj" (".scss")
"\\.scss$" (".config.json" ".config.js" ".config.yaml" ".config.yml" ".hbs" ".mustache" ".twig" ".nunj")
"\\.js$\\|\\.json$\\|\\.yaml$\\|\\.yml$" (".hbs" ".mustache" ".twig" ".nunj" ))))
;;@ Find corresponding files
(defun my/get--corresponding-file-extension (file hash-table)
"Returns the corresponding extensions if FILE has one of the
extensions included in the keys of HASH-TABLE"
(let ((extension nil))
(maphash (lambda (key value)
(when (string-match key file)
(setq extension value)))
hash-table)
extension))
(defun my/find--corresponding-file (file extensions)
"Find a corresponding file for FILE based on the EXTENSIONS to search for."
(if (null extensions)
nil
(let* ((base-filename (file-name-sans-extension file))
(searched-filename
(concat base-filename (car extensions)))
;; files with two or more dots in extension.
(searched-filename2
(concat (replace-regexp-in-string "\\..*" "" base-filename)
(car extensions))))
(cond
((file-exists-p searched-filename)
searched-filename)
((file-exists-p searched-filename2)
searched-filename2)
(t (my/find--corresponding-file file (cdr extensions)))))))
(defun my/goto-primary-file ()
"Go to the primary file that corresponds to the current buffer"
(interactive)
(let* ((extensions (my/get--corresponding-file-extension (replace-regexp-in-string "<.*" "" (buffer-name))
primary-ext-table))
(file (my/find--corresponding-file (buffer-name) extensions)))
(if file
(find-file file)
(error "Unable to find a corresponding file"))))