如何使一个Lisp函数调用java同时知道包? [英] How to make a Lisp function call java while being aware of packages?
问题描述
(defun java-run-current-file()
运行java程序当前文件对应于
(interactive)
(shell-command
(concatjava
(file-name-sans-extension
(file-name-nondirectory(buffer-file-name))))))
它可以通过剥离其路径和扩展名的当前文件名,并将其用作 java
的参数,这是从文件所在的路径运行。这种方法的问题是,如果当前文件是包的一部分,那么
-
java
必须以包名称和一个点为前缀, -
java
必须从包含该包的目录。
所以例如,如果文件是file.java,包名是pkg 从包含目录pkg(放置file.java的目录的父目录)的目录中调用java
作为 java pkg.file
。
如何修改函数以了解包,并相应地将参数构造为 java
我想可以通过搜索当前文件来解决这个问题,例如
PKG;
如果发现它使用该包名称调用 java
请尝试以下代码来搜索当前文件的包声明:
(save-excursion
(goto-char(point-min))
当(重新搜索转发^ \\s * package\\\s + \\(。* \\);(point-max)t)
(match-字符串1)))
这将返回一个包
声明和分号。如果没有发现这样的声明,它将返回
nil
。
(请注意,如果有评论,可能会失败在一个C风格的多行注释( / * ... * / >)中,在实际包声明之前的某个地方声明了
package
code>))
为了更改运行shell命令的目录,请使用 cd
函数。因为在Java中,包结构应该反映目录结构,可以使用上面的代码确定的包信息来找出你的源代码的基本目录:
(let((directory(file-name-directory(buffer-file-name)))
(sub-dirs(reverse(split-string package \\。))))
(而sub-dirs
(if(string-match(concat^ \\(。* / \\)(regexp -cote(car sub-dirs))/ $)目录)
(setq目录(match-string 1目录)
sub-dirs(cdr sub-dirs))
包不匹配目录结构)))
(cd目录))
你可以使用这个代码来扩展你的函数,如下所示:
(defun java-run-current- file()
运行当前文件对应的java程序
(interactive)
(let * ((package(save-excursion
(goto-char(point-min))
(when(re-search-forward^ \\s * package\\s + \(。* \\);(point-max)t)
(match-string 1))))
(directory(file-name-directory(buffer-file-name )$)
(如果目录
(setq目录(文件truename目录))
(错误当前缓冲区未访问文件))
(当包
(setq sub-dirs(reverse(split-string package\\。)))
(while sub-dirs
(if(string-match(concat^ \\(。* / \\)(regexp-quote(car sub-dirs))/ $)directory)
(setq目录(match-string 1目录)
sub-dirs(cdr sub-dirs))
(错误包不匹配目录结构))))
(cd目录)
(shell命令
(conca tjava
(如果包(concat package。))
(file-name-sans-extension
(file-name-nondirectory(buffer-file-name) ))))))
In Emacs use a Lisp function to run the Java program the current file correspond to.
(defun java-run-current-file ()
"Runs the java program the current file correspond to"
(interactive)
(shell-command
(concat "java "
(file-name-sans-extension
(file-name-nondirectory (buffer-file-name))))))
It works by stripping the current file name of its path and extension and using it as an argument to java
which is run from the path where the file is at. The problem with this approach is that if the current file is part of a package then
- the argument to
java
has to be prefixed with the package name and a dot, and java
has to be run from the directory containing the package.
So for example if the file is file.java and the package name is pkg java
is called as java pkg.file
from the directory containing the directory pkg (the parent directory of the directory where file.java is placed).
How can I modify the function to be aware of packages and construct the argument to java
accordingly? I guess one might solve this by searching the current file for a package declaration, such as
package pkg;
and if it finds one it uses that package name to call java
appropriately.
Try the following code to search the current file for a package declaration:
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^\\s *package\\s +\\(.*\\);" (point-max) t)
(match-string 1)))
This will return the value between a package
declaration and the semi-colon. It will return nil
if no such declaration is found.
(Beware that this might fail if there is a commented-out package
declaration somewhere before the actual package declaration, in a C-style, multi-line comment (/* ... */
).)
In order to change the directory from which a shell command is run, use the cd
function. Since in Java the package structure should reflect the directory structure, you can use the package information determined by the above code to figure out the base directory of your source code:
(let ((directory (file-name-directory (buffer-file-name)))
(sub-dirs (reverse (split-string package "\\."))))
(while sub-dirs
(if (string-match (concat "^\\(.*/\\)" (regexp-quote (car sub-dirs)) "/$") directory)
(setq directory (match-string 1 directory)
sub-dirs (cdr sub-dirs))
(error "Package does not match directory structure")))
(cd directory))
You may use this code to extend your function like so:
(defun java-run-current-file ()
"Runs the java program the current file corresponds to"
(interactive)
(let* ((package (save-excursion
(goto-char (point-min))
(when (re-search-forward "^\\s *package\\s +\\(.*\\);" (point-max) t)
(match-string 1))))
(directory (file-name-directory (buffer-file-name)))
sub-dirs)
(if directory
(setq directory (file-truename directory))
(error "Current buffer is not visiting a file"))
(when package
(setq sub-dirs (reverse (split-string package "\\.")))
(while sub-dirs
(if (string-match (concat "^\\(.*/\\)" (regexp-quote (car sub-dirs)) "/$") directory)
(setq directory (match-string 1 directory)
sub-dirs (cdr sub-dirs))
(error "Package does not match directory structure"))))
(cd directory)
(shell-command
(concat "java "
(if package (concat package ".") "")
(file-name-sans-extension
(file-name-nondirectory (buffer-file-name)))))))
这篇关于如何使一个Lisp函数调用java同时知道包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!