如何模块化处理Ja​​va文件的两个Lisp函数的通用function?

我使用一个Lisp函数来编译当前的Java文件,另一个用于运行它。 这两个函数使用相同的function来获取包名称和编译/运行的相应目录(此function作为另一个问题的答案发布)。 我想模块化这些函数的常用function,即从(let*到但不包括(cd 。我怎么能这样做?)

作为奖励,我想撤消目录的更改( cd :ing),因为这些function是为了避免意外行为,例如从parten目录中查找文件( Cx Cf )。 有人建议这可以通过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))) 

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

 ;; 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约定。 但同样,希望这足以让你开始。