查找项目中文件的相对路径

时间:2013-08-21 20:16:09

标签: emacs elisp

我的项目文件设置为以下格式:

/home/user/proj/source
/home/user/proj/source/src1
/home/user/proj/source/src1
/home/user/proj/header ...etc

我可以在查看任何源文件时找到项目路径

"/home/user/proj"

此外,(buffer-file-name)给出了给定源文件的完整绝对路径。

如何编写一个提取源文件相对路径的lisp函数?

意思是,如果我正在观看

/home/user/proj/source/src1/file.c

我想要路径

"source/src1/file.c"

以下函数为我提供了项目路径:

(defun upward-find-file (filename &optional startdir)
  (let ((dirname (expand-file-name
          (if startdir startdir ".")))
    (found nil) ; found is set as a flag to leave loop if we find it
    (top nil))  ; top is set when we get
            ; to / so that we only check it once
    ; While we've neither been at the top last time nor have we found
    ; the file.
    (while (not (or found top))
      ; If we're at / set top flag.
      (if (string= (expand-file-name dirname) "/")
      (setq top t))
      ; Check for the file
      (if (file-exists-p (expand-file-name filename dirname))
      (setq found t)
    ; If not, move up a directory
    (setq dirname (expand-file-name ".." dirname))))
    ; return statement
    (if found (concat dirname "/") nil)))

我在主项目文件夹中总是有“Makefile”,所以

(setq dirname (upward-find-file "Makefile" startdir))

照顾好。

4 个答案:

答案 0 :(得分:5)

尝试locate-dominating-filefile-relative-name

(let ((fname (buffer-file-name)))
  (file-relative-name fname (locate-dominating-file fname "Makefile")))

N.B。如果找不到任何内容,locate-dominiating-file会返回nil

答案 1 :(得分:1)

这个怎么样:

(defun file-name-make-relative (filename reference)
  (interactive)
  (let ((reduced-path-reference)
        (common-pos 0)
        (depth 0)
        (pos 0)
        (retval ""))
    (while (eq (aref filename common-pos) (aref reference common-pos))
      (setq common-pos (+ common-pos 1)))
    (setq reduced-path-reference (substring reference (+ common-pos 1)))
    (while (< pos (length (substring reference (+ common-pos 1))))
      (if (eq (aref reduced-path-reference pos) (aref "/" 0))
          (setq depth (+ depth 1)))
      (setq pos (+ pos 1)))
    (dotimes (i depth)
      (setq retval (concat retval "../")))
    (setq retval (concat retval (substring filename common-pos)))
    retval))

它没有经过彻底的测试,但是,在我的简单测试用例中,它按预期工作。给定一个文件filename和一个引用目录reference(必须有尾随斜杠,我不记得哪个函数自动执行此操作,有人可以注释?)此函数将计算{{1}的相对路径到reference

示例:

filename

结果:
  

(file-name-make-relative "/usr/local/bin/exec" "/usr/local/root/bin/")

答案 2 :(得分:1)

安装f.el,一个全面的文件和目录操作库。然后运行函数f-relative

(f-relative "some/path/is/long" "some/path/was/short") ; => "../../is/long"

答案 3 :(得分:0)

您可以根据需要调整此代码:

(defun java-package-name (file)
  "Generates package name for FILE, based on path."
  (let* ((f (file-name-directory file))
         (rem
          (car
           (sort
            (delq nil
                  (mapcar
                   (lambda(x)
                     (and (string-match (expand-file-name x) f) 
                          (substring f (match-end 0))))
                   (parse-colon-path (getenv "CLASSPATH"))))
            (lambda (a b) (< (length a) (length b)))))))
    (cond
     ((null rem)
      "Not on CLASSPATH.")
     ((= 0 (length rem))
      "At root of CLASSPATH")
     (t
      (mapconcat
       #'downcase
       (delete "" (split-string rem "[\\\\/]"))
       ".")))))