How to make a Lisp function call java while being aware of packages?

丶灬走出姿态 提交于 2019-12-07 12:33:52

问题


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

  1. the argument to java has to be prefixed with the package name and a dot, and
  2. 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.


回答1:


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)))))))



回答2:


Either use a proper Java IDE (you will eventually if you do this on a regular basis) or read the file to parse the package line.

Also note that you will most likely also need to specify the compilation root folder (or cd to it) to be able to set the class path properly.

For deriving the actual class name, reading the file and searching for "package (.*);" (matching newlines too) would most likely be good enough.

To be frank, when I need to work like this, I write a small script (bat-file under WIndows) which does what I need. The reason is that I usually need a lot of jarfiles on the classpath too, which eventually boils down to me needing to specify the whole command line anyway.



来源:https://stackoverflow.com/questions/12546437/how-to-make-a-lisp-function-call-java-while-being-aware-of-packages

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!