# Find other file / Teach me elisp

**URL:** <https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226>\
**Category:** Emacs Lisp\
**Created:** [February 7, 2024, 7:56pm UTC](https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226 "2024-02-07T19:56:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![foomanchew](https://avatars.discourse-cdn.com/v4/letter/f/4bbf92/32.png) [@foomanchew](https://forum.systemcrafters.net/u/foomanchew)\
**Post date:** [February 7, 2024, 7:56pm UTC](https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226/1 "2024-02-07T19:56:44Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![mirkoh](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@mirkoh](https://forum.systemcrafters.net/u/mirkoh)\
**Post date:** [February 8, 2024, 6:03am UTC](https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226/2 "2024-02-08T06:03:17Z")

</div>

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.

```lisp
(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))))))

```

---

<div class="post-metadata">

**Author:** ![foomanchew](https://avatars.discourse-cdn.com/v4/letter/f/4bbf92/32.png) [@foomanchew](https://forum.systemcrafters.net/u/foomanchew)\
**Post date:** [February 12, 2024, 10:02pm UTC](https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226/3 "2024-02-12T22:02:37Z")

</div>

Thanks. That is helpful. But I would like more complex patterns / the ability to have more then two related files.

---

<div class="post-metadata">

**Author:** ![mirkoh](https://avatars.discourse-cdn.com/v4/letter/m/eb9ed0/32.png) [@mirkoh](https://forum.systemcrafters.net/u/mirkoh)\
**Post date:** [February 12, 2024, 10:32pm UTC](https://forum.systemcrafters.net/t/find-other-file-teach-me-elisp/226/4 "2024-02-12T22:32:02Z")

</div>

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.

```auto
(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"))))

```
