2020-10-23 12:34:23 +09:00
|
|
|
|
;;; julia-vterm.el --- A mode for Julia REPL using vterm -*- lexical-binding: t -*-
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; Copyright (C) 2020 Shigeaki Nishina
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; Author: Shigeaki Nishina
|
|
|
|
|
;; Maintainer: Shigeaki Nishina
|
2020-10-07 14:08:31 +09:00
|
|
|
|
;; Created: March 11, 2020
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;; URL: https://github.com/shg/julia-vterm.el
|
2020-10-09 13:57:30 +09:00
|
|
|
|
;; Package-Requires: ((emacs "25.1") (vterm "0.0.1"))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;; Version: 0.10
|
2020-10-07 14:08:31 +09:00
|
|
|
|
;; Keywords: languages, julia
|
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; This file is not part of GNU Emacs.
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;;; License:
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; This program is free software: you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or (at
|
|
|
|
|
;; your option) any later version.
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;;
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; This program is distributed in the hope that it will be useful, but
|
|
|
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
;; General Public License for more details.
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;;
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
|
;; along with this program. If not, see https://www.gnu.org/licenses/.
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;; Provides a major-mode for inferior Julia process that runs in vterm, and a
|
|
|
|
|
;; minor-mode that extends julia-mode to support interaction with the inferior
|
|
|
|
|
;; Julia process.
|
|
|
|
|
|
|
|
|
|
;;; Usage:
|
|
|
|
|
|
|
|
|
|
;; You must have julia-mode and vterm installed.
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;; Install julia-vterm.el manually using package.el
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;;
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;; (package-install-file "/path-to-download-dir/julia-vterm.el")
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;;
|
|
|
|
|
;; Eval the following line. Add this line to your init file to enable this
|
|
|
|
|
;; mode in future sessions.
|
|
|
|
|
;;
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;; (add-hook 'julia-mode-hook #'julia-vterm-mode)
|
2020-10-09 11:49:45 +09:00
|
|
|
|
;;
|
|
|
|
|
;; Now you can interact with an inferior Julia REPL from a Julia buffer.
|
|
|
|
|
;;
|
|
|
|
|
;; C-c C-z in a julia-mode buffer to open an inferior Julia REPL buffer.
|
|
|
|
|
;; C-c C-z in the REPL buffer to switch back to the script buffer.
|
|
|
|
|
;; C-<return> in the script buffer to send region or current line to REPL.
|
|
|
|
|
;;
|
|
|
|
|
;; See the code below for a few more key bidindings.
|
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(require 'vterm)
|
|
|
|
|
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;;----------------------------------------------------------------------
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defgroup julia-vterm-repl nil
|
2020-03-11 10:30:20 +00:00
|
|
|
|
"A major mode for inferior Julia REPL"
|
|
|
|
|
:group 'julia)
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defvar julia-vterm-repl-buffer-name "*julia-repl*")
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defvar julia-vterm-repl-program "julia")
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defvar-local julia-vterm-repl-script-buffer nil)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defvar julia-vterm-repl-mode-map
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(let ((map (make-sparse-keymap)))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(define-key map (kbd "C-c C-z") #'julia-vterm-repl-switch-to-script-buffer)
|
|
|
|
|
(define-key map (kbd "M-k") #'julia-vterm-repl-clear-buffer)
|
|
|
|
|
(define-key map (kbd "C-c C-t") #'julia-vterm-repl-copy-mode)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(define-key map (kbd "C-l") #'recenter-top-bottom)
|
|
|
|
|
map))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(define-derived-mode julia-vterm-repl-mode vterm-mode "Inf-Julia"
|
2020-03-11 10:30:20 +00:00
|
|
|
|
"A major mode for inferior Julia REPL."
|
2020-10-23 12:34:23 +09:00
|
|
|
|
:group 'julia-vterm-repl)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-repl-buffer ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Return the inferior Julia REPL buffer `*julia-repl*`.
|
|
|
|
|
If the buffer doesn't exist, create one and return it. If there's already the
|
|
|
|
|
buffer and the inferior Julia REPL is running, return the buffer. If the
|
|
|
|
|
buffer exists but the process is not running, kill the buffer and create a new
|
|
|
|
|
one."
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(if-let ((buffer (get-buffer julia-vterm-repl-buffer-name))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(proc (with-current-buffer buffer vterm--process)))
|
|
|
|
|
buffer
|
|
|
|
|
(if buffer (kill-buffer buffer))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(let ((buffer (generate-new-buffer julia-vterm-repl-buffer-name))
|
|
|
|
|
(vterm-shell julia-vterm-repl-program))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(with-current-buffer buffer
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-repl-mode))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
buffer)))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-repl ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Create an inferior Julia REPL buffer `*julia-repl*` and open it.
|
|
|
|
|
If there's already one with the process alive, just open it."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(interactive)
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(pop-to-buffer-same-window (julia-vterm-repl-buffer)))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-repl-switch-to-script-buffer ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Switch to the script buffer that opened this Julia REPL buffer."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(interactive)
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(if (and (boundp 'julia-vterm-repl-script-buffer) (buffer-live-p julia-vterm-repl-script-buffer))
|
|
|
|
|
(switch-to-buffer-other-window julia-vterm-repl-script-buffer)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(message "The script buffer does not exist.")))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-repl-clear-buffer ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Clear the content of the Julia REPL buffer."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(save-excursion
|
2020-08-30 23:10:51 +09:00
|
|
|
|
(goto-char (point-min))
|
2020-10-08 19:18:05 +09:00
|
|
|
|
(vterm-clear 1)))
|
2020-03-13 02:42:28 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defvar julia-vterm-repl-copy-mode-map
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(let ((map (make-sparse-keymap)))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(define-key map (kbd "C-c C-t") #'julia-vterm-repl-copy-mode)
|
|
|
|
|
(define-key map [return] #'julia-vterm-repl-copy-mode-done)
|
|
|
|
|
(define-key map (kbd "RET") #'julia-vterm-repl-copy-mode-done)
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(define-key map (kbd "C-c C-r") #'vterm-reset-cursor-point)
|
|
|
|
|
map))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(define-minor-mode julia-vterm-repl-copy-mode
|
2020-03-13 02:42:28 +00:00
|
|
|
|
"Toggle copy mode."
|
2020-10-23 12:34:23 +09:00
|
|
|
|
:group 'julia-vterm-repl
|
2020-03-13 02:42:28 +00:00
|
|
|
|
:lighter " VTermCopy"
|
2020-10-23 12:34:23 +09:00
|
|
|
|
:keymap julia-vterm-repl-copy-mode-map
|
|
|
|
|
(when julia-vterm-repl-copy-mode
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(message "Start copy mode")
|
|
|
|
|
(use-local-map nil)
|
|
|
|
|
(vterm-send-stop)))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-repl-copy-mode-done ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Save the active region to the kill ring and exit copy mode."
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(if (region-active-p)
|
|
|
|
|
(kill-ring-save (region-beginning) (region-end))
|
|
|
|
|
(user-error "No active region"))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-repl-copy-mode -1)
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(vterm-reset-cursor-point)
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(use-local-map julia-vterm-repl-mode-map)
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(vterm-send-start)
|
|
|
|
|
(message "End copy mode"))
|
|
|
|
|
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-03-11 10:30:20 +00:00
|
|
|
|
;;----------------------------------------------------------------------
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defgroup julia-vterm nil
|
2020-10-09 18:16:14 +09:00
|
|
|
|
"A minor mode to interact with an inferior Julia REPL."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
:group 'julia)
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defcustom julia-vterm-hook nil
|
2020-10-09 18:16:14 +09:00
|
|
|
|
"Hook run after starting a Julia script buffer with an inferior Julia REPL."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
:type 'hook
|
2020-10-23 12:34:23 +09:00
|
|
|
|
:group 'julia-vterm)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-switch-to-repl-buffer ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Switch to the REPL buffer if one already exists, or open a new REPL buffer."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(let ((current-script-buffer (current-buffer))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(inferior-buffer (julia-vterm-repl-buffer)))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(with-current-buffer inferior-buffer
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(setq julia-vterm-repl-script-buffer current-script-buffer)
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(switch-to-buffer-other-window inferior-buffer))))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-send-return-key ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Send a return key to the Julia REPL buffer."
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(with-current-buffer (julia-vterm-repl-buffer)
|
2020-10-02 08:56:13 +09:00
|
|
|
|
(vterm-send-return)))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-paste-string (string)
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Send STRING to the Julia REPL buffer using brackted paste mode."
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(with-current-buffer (julia-vterm-repl-buffer)
|
2020-10-02 08:56:13 +09:00
|
|
|
|
(vterm-send-string string t)))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-send-current-line ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Send the current line to the Julia REPL buffer, and move to the next line.
|
|
|
|
|
This sends a newline after the content of the current line even if there's no
|
|
|
|
|
newline at the end. A newline is also inserted after the current line of the
|
|
|
|
|
script buffer."
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(interactive)
|
2020-10-07 13:23:04 +09:00
|
|
|
|
(save-excursion
|
|
|
|
|
(end-of-line)
|
|
|
|
|
(let ((clmn (current-column))
|
|
|
|
|
(char (char-after))
|
|
|
|
|
(line (string-trim (thing-at-point 'line t))))
|
|
|
|
|
(unless (and (zerop clmn) char)
|
|
|
|
|
(when (/= 0 clmn)
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-paste-string line)
|
|
|
|
|
(julia-vterm-send-return-key)
|
2020-10-07 13:23:04 +09:00
|
|
|
|
(if (not char)
|
|
|
|
|
(newline))))))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
(forward-line))
|
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-send-region-or-current-line ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Send the content of region if region is active, or send the current line."
|
2020-10-04 01:51:50 -07:00
|
|
|
|
(interactive)
|
|
|
|
|
(if (use-region-p)
|
|
|
|
|
(progn
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-paste-string
|
2020-10-07 14:08:31 +09:00
|
|
|
|
(buffer-substring-no-properties (region-beginning) (region-end)))
|
|
|
|
|
(deactivate-mark))
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-send-current-line)))
|
2020-10-04 01:51:50 -07:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(defun julia-vterm-send-buffer ()
|
2020-10-09 11:49:45 +09:00
|
|
|
|
"Send the whole content of the script buffer to the Julia REPL buffer."
|
2020-03-13 02:42:28 +00:00
|
|
|
|
(interactive)
|
|
|
|
|
(save-excursion
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(julia-vterm-paste-string (buffer-string))))
|
2020-03-13 02:42:28 +00:00
|
|
|
|
|
2020-10-09 10:02:50 +09:00
|
|
|
|
;;;###autoload
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(define-minor-mode julia-vterm-mode
|
2020-03-11 10:30:20 +00:00
|
|
|
|
"A minor mode for a Julia script buffer that interacts with an inferior Julia REPL."
|
|
|
|
|
nil "⁂"
|
2020-10-23 12:34:23 +09:00
|
|
|
|
`((,(kbd "C-c C-z") . julia-vterm-switch-to-repl-buffer)
|
|
|
|
|
(,(kbd "C-<return>") . julia-vterm-send-region-or-current-line)
|
|
|
|
|
(,(kbd "C-c C-b") . julia-vterm-send-buffer)))
|
2020-03-11 10:30:20 +00:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
(provide 'julia-vterm)
|
2020-10-07 14:08:31 +09:00
|
|
|
|
|
2020-10-23 12:34:23 +09:00
|
|
|
|
;;; julia-vterm.el ends here
|