Cho đến nay tôi đã phát hiện ra rằng sinh ra một quy trình Emacs mới là một giải pháp.
Đây là những gì tôi đã làm.
1. Thêm một chức năng để bắt đầu một quá trình emacs bên ngoài.
init.el
(defvar my/async-emacs-repl-org-babel-init-file "~/.emacs.d/org-babel-async-init" "File to load on executing async babel evaluation.")
(defun my/async-emacs-repl--start (process-name init-file)
"Start a new Emacs process as a REPL server."
(async-shell-command (concat
"TERM=vt200 emacs --batch -nw"
" --eval '(load \"" init-file "\")'"
" --eval '(while t (print (eval (read))))'"
)
process-name))
(defun my/async-emacs-repl--org-babel--start-server ()
"Starts an Emacs process for async org-babel execution."
(my/async-emacs-repl--start "*org-babel-async*" my/async-emacs-repl-org-babel-init-file))
(defun my/async-emacs-repl--org-babel--start-if-not-exists ()
"Starts an Emacs process if the process does not exist."
(if (not (get-buffer-process "*org-babel-async*")) (my/async-emacs-repl--org-babel--start-server)))
(defun my/async-emacs-repl--org-babel--execute--build-command (file-name line-number)
"Build the command for executing `org-babel-execute-src-block'."
(concat
"(progn"
" (find-file \"" file-name "\")"
" (revert-buffer t t)"
" (goto-line " (number-to-string line-number) ")"
" (org-babel-execute-src-block t)"
" (save-buffer)"
")"
"\n"))
(defun my/async-emacs-repl--org-babel--execute (process-name file-name line-number)
"Sends the command to the server to run the code-block the cursor is at."
(process-send-string
process-name
(my/async-emacs-repl--org-babel--execute--build-command file-name line-number)))
(defun my/async-emacs-repl-org-babel-do-execute ()
"Run org babel execution at point."
(my/async-emacs-repl--org-babel--execute "*org-babel-async*" (buffer-file-name) (line-number-at-pos)))
(defun my/async-emacs-repl-org-babel-execute ()
"Run by the user. Executes command. Starts buffer if not exists."
(interactive)
(save-buffer)
(my/async-emacs-repl--org-babel--start-if-not-exists)
(my/async-emacs-repl-org-babel-do-execute))
2. Thêm tệp cấu hình để tải trong quy trình emacs mới.
Các chức năng trên bắt đầu emacs trong --batch
chế độ. Do đó, init.el bình thường sẽ không được tải.
Thay vào đó, chúng tôi muốn tạo một tệp cấu hình ngắn hơn (để tải đường dẫn, v.v.).
Đường dẫn đến tệp cấu hình mới của chúng tôi được lưu trữ trong async-emacs-repl-org-babel-init-file
đoạn trích ở trên.
org-babel-async-init.el
;; 1
(package-initialize)
;; 2
(setq org-confirm-babel-evaluate nil)
;; 3
(let ((my/org-babel-evaluated-languages
'(emacs-lisp
ditaa
python
ruby
C
matlab
clojure
sh
dot
plantuml)))
(org-babel-do-load-languages
'org-babel-load-languages
(mapcar (lambda (lang)
(cons lang t))
my/org-babel-evaluated-languages)))
Ở đây chúng tôi ...
- Thêm đường dẫn gói.
- Nói với chế độ org để không hỏi có thực thi khối mã hay không.
- Nói với org-babel những ngôn ngữ cần thiết.
Chú thích 1: Không có cài đặt này, việc đánh giá sẽ thất bại với "No org-babel-execute function for $lang!"
Chú thích 2: Tất nhiên bạn có thể tải init.el bình thường thay vì tạo tệp cấu hình mới, nếu bạn muốn. Làm điều đó bằng cách thêm (setq org-babel-async-init-file "~/.emacs.d/init")
vào của bạn init.el
. Nhưng tôi nghĩ việc tạo một tệp cấu hình cho tác vụ này đơn giản hơn.
3. Ngoài ra ...
Thêm vào init.el
;; This will stop the new process buffer from getting focus.
(setq display-buffer-alist (append display-buffer-alist '(("*org-babel-async*" display-buffer-no-window))))
;; This will automatically show the result section.
(global-auto-revert-mode 1)
Thêm vào org-babel-async-init.el
;; This will skip the "Save anyway?" confirmation of automatically saving the file when you also edited the buffer from Emacs while an asynchronous process is running.
(defun advice:verify-visited-file-modtime (orig-func &rest args) t)
(advice-add 'verify-visited-file-modtime :around 'advice:verify-visited-file-modtime)
;; This will skip the "Select coding system" prompt that appears when the result is inserted. This may vary among environments.
(setq coding-system-for-write 'utf-8)
;; This will skip the "changed on disk; really edit the buffer?" checking.
(defun ask-user-about-supersession-threat (fn) "blatantly ignore files that changed on disk")
Thêm vào org-babel-async-init.el (bạn có thể không cần những thứ này. Đây là cho MATLAB)
;; This will set MATLAB cli path.
(setq-default matlab-shell-command "/Applications/MATLAB_R2016a.app/bin/matlab")
;; The MATLAB cli path can be obtained by running `fullfile(matlabroot, 'bin')` in your MATLAB.
;; This will stop MATLAB from showing the splash (the MATLAB logo) at the beginning.
(setq-default matlab-shell-command-switches '("-nodesktop" "-nosplash"))
Thêm vào org-babel-async-init.el (bạn có thể không cần những thứ này. Chúng dành cho Julia, R và các ngôn ngữ khác sử dụng ESS.)
;; This will enable :session header in Julia and other languages that use ESS (Emacs speaks statistics).
(load "/path/to/ess-site")
;; This will suppress ESS from prompting for session directory.
(setq ess-ask-for-ess-directory nil)
4. Cách sử dụng
(Sau khi thiết lập ở trên.)
- Di chuyển con trỏ đến đoạn mã bạn muốn thực thi.
- Chạy
M-x my/async-emacs-repl-org-babel-execute
(thay vì làm C-c C-c
). Điều này sẽ bắt đầu một quá trình Emacs bên ngoài như một máy chủ REPL nếu cần, và sau đó thực thi khối nguồn bạn đang ở.
Sự nhìn nhận
Tôi đã học được ý tưởng bắt đầu một quá trình emacs để đánh giá org-babel từ bài đăng này . Tôi xin cảm ơn tác giả.
Nhận xét để tùy chỉnh
Ý tưởng ở đây rất đơn giản. Bắt đầu một quá trình emacs mới dưới dạng REPL cho Elisp, thực hiện find-file
với cùng một tệp .org mà chúng tôi đang chỉnh sửa, goto-line
đến cùng một điểm con trỏ, chạy org-babel-execute-src-block
, save-buffer
. Dừng thoát cho đến khi người dùng dừng quá trình (Nếu không, biểu đồ sẽ biến mất ngay sau khi chúng được hiển thị). Một cách tự nhiên có thể nghĩ về việc mở rộng điều này bằng cách:
- Sử dụng chế độ org
C-c C-c
thay vì chạy các chức năng bằng tay / cài đặt một tổ hợp phím mới (có thể đạt được bằng lời khuyên).
- Điều kiện chuyển đổi tên quá trình theo: biến phiên và ngôn ngữ
- Điều kiện chuyển đổi các tập tin init dựa trên ngôn ngữ.
Trên thực tế, sự thành công của phương pháp này đối với tôi dường như đang cho thấy một cách chung để phát triển các tính năng không đồng bộ trong Emacs. Tạo một lớp "lệnh", thêm tập lệnh để thực hiện các tác vụ và có một khung để bắt đầu và sử dụng lại các quy trình emacs. Giống như khung công tác Symfony của PHP (PHP không có chủ đề) có các tính năng Lệnh.
Chỉnh sửa lịch sử
Mã tái cấu trúc (2016-04 / 02). Giải pháp hiện đang sử dụng lại một quy trình Emacs (2016-04-02). Giải pháp hiện đã được đơn giản hóa và chỉ có một interactive
lệnh để chạy (2016-04-02. Đã thêm cấu hình (2016-04-12).