1

我使用一个 Lisp 函数来编译当前的 Java 文件并使用另一个来运行它。这两个函数使用相同的功能来获取包名称和适当的目录来编译/运行(这个功能是作为另一个问题的答案发布的)。我想将这些功能的通用功能模块化,即 from (let*to 但不包括(cd. 我怎样才能做到这一点?

作为奖励,我想撤消对目录(cd:ing)的更改,因为这些功能已完成以避免意外行为,例如C-x C-f从 parten 目录开始查找文件()。有人建议,这可以通过unwind-protect.

(add-hook 'java-mode-hook
      (lambda ()

    (defun java-compile-current-file ()
      "Compiles the current file with javac"
      (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)
        (compile
         (concat "javac -Xlint:all " ; Tog bort -Werror från
                    ; argumenten. För
                    ; gnälligt!
             (if package (concat package "/") "")
             (file-name-nondirectory (buffer-file-name))))))

    (local-set-key [(f8)] 'java-compile-current-file)

    ;; https://stackoverflow.com/a/12548762/789593
    (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)))))))

    (local-set-key [(f7)] 'java-run-current-file)))
4

1 回答 1

1

这是一个粗略的、未经测试的代码重构。它不是特别优雅或惯用的,但至少应该足以让您入门。

;; 1. Refactored `java-get-package' into its own `defun'
;; 2. Refactored `java-package-directory' into its own `defun'
;; 3. Broke out `defun's outside of `java-mode-hook'
;; 4. Use (let ((default-directory ...) ...) instead of (cd ...) (...)
;; 5. Broke out keystroke assignments into `my-java-mode-hook'

(defun java-get-package ()
  "Get package definition before point"
  (interactive)
  (save-excursion
    (save-match-data  ;; Added; you want this too
      (goto-char (point-min))
      (when (re-search-forward "^\\s *package\\s +\\(.*\\);"
                               (point-max) t)
        (match-string 1)) )) )

(defun java-package-directory (package)
  "Get package directory of PACKAGE in current buffer"
  (let ((directory (file-name-directory (buffer-file-name)))
        sub-dirs)
    (if directory
        (setq directory (file-truename directory))
      (error "Current buffer is not visiting a file"))
    (save-match-data
      (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") ) ) )
    directory) )

(defun java-compile-current-file ()
 "Compiles the current file with javac"
 (interactive)
 (let* ((package (java-get-package))
        (default-directory (java-package-directory package)) )
   (compile
    (concat "javac -Xlint:all " ; Removed too noisy -Werror
        (if package (concat package "/") "")
        (file-name-nondirectory (buffer-file-name)) ) ) ))

(defun java-run-current-file ()
 "Runs the java program the current file corresponds to"
 (interactive)
 (let* ((package (java-get-package))
        (default-directory (java-package-directory package)) )
   (shell-command
    (concat "java "
        (if package (concat package ".") "")
        (file-name-sans-extension
         (file-name-nondirectory (buffer-file-name)) ) )) ))

(defun my-java-mode-hook () "Stuff to run when entering Java mode"
    (local-set-key [(f7)] 'java-run-current-file)
    (local-set-key [(f8)] 'java-compile-current-file) )

(add-hook 'java-mode-hook #'my-java-mode-hook)

新函数可能应该接受一个缓冲区参数,以便您可以在与您所在的缓冲区不同的缓冲区上调用它们,以实现一般可用性和遵守常见的 Emacs 约定。但同样,希望这足以让你开始。

于 2012-10-16T09:18:38.260 回答