1

1 つの Lisp 関数を使用して現在の Java ファイルをコンパイルし、別の Lisp 関数を使用してそれを実行します。どちらの関数も同じ機能を使用して、パッケージ名とコンパイル/実行する適切なディレクトリを取得します (この機能は別の質問への回答として投稿されました)。これらの関数の共通機能をモジュール化したいと考えて(let*(cdます。これどうやってするの?

おまけとして、parten ディレクトリから始まるcdファイル ( ) を見つけるなどの予期しない動作を回避するために関数が実行されるため、ディレクトリの変更 (:ing)を元に戻したいと思います。C-x C-fこれは、によって達成できることが示唆され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 に答える