mirror of
https://github.com/carp-lang/Carp.git
synced 2024-11-05 04:44:12 +03:00
refactor: Move emacs-mode to separate repo (#981)
This commit is contained in:
parent
a270365553
commit
3192d54ae9
@ -4,28 +4,7 @@
|
||||
[https://github.com/hellerve/carp-vim](https://github.com/hellerve/carp-vim)
|
||||
|
||||
## Emacs
|
||||
This repo contains a hacked-together Emacs package that depends on Clojure mode being installed.
|
||||
It will hopefully be rewritten and put into one of the package managers eventually, for now you can do something like this to config it:
|
||||
|
||||
```
|
||||
(add-to-list 'load-path "~/your/path/to/Carp/emacs")
|
||||
|
||||
(require 'carp-mode)
|
||||
(require 'inf-carp-mode)
|
||||
|
||||
(add-to-list 'auto-mode-alist '("\\.carp\\'" . carp-mode))
|
||||
```
|
||||
|
||||
For Flycheck:
|
||||
```
|
||||
(require 'carp-flycheck)
|
||||
|
||||
(add-hook 'carp-mode-hook
|
||||
(lambda ()
|
||||
(flycheck-mode 1)))
|
||||
```
|
||||
|
||||
To start an interactive session, make sure `carp` is in your path (inside Emacs) and execute `M-x run-carp`.
|
||||
[https://github.com/carp-lang/carp-emacs](https://github.com/carp-lang/carp-emacs)
|
||||
|
||||
# Atom
|
||||
[language-carp](https://atom.io/packages/language-carp) offers highlight with both TextMate and Tree-sitter, where tree-sitter grammar is more powerful.
|
||||
|
@ -1,20 +0,0 @@
|
||||
(require 'flycheck)
|
||||
|
||||
(flycheck-define-checker carp-checker
|
||||
"A Carp syntax checker.
|
||||
|
||||
See URL `http://github.com/carp-lang/Carp/'."
|
||||
:command ("carp" "--check" source)
|
||||
:error-patterns ((error line-start space (message) "\n At line " line ", column " column " in '" (file-name) "'" line-end)
|
||||
(error line-start (file-name) ":" line ":" column " " (message) line-end))
|
||||
:modes (carp-mode))
|
||||
|
||||
(eval-after-load 'flycheck
|
||||
'(add-to-list 'flycheck-checkers 'carp-checker))
|
||||
|
||||
;; (flycheck-parse-error-with-patterns
|
||||
;; " At line 11, column 3 in 'foo.carp'"
|
||||
;; (flycheck-checker-get 'carp-checker 'error-patterns)
|
||||
;; 'carp-checker)
|
||||
|
||||
(provide 'carp-flycheck)
|
@ -1,7 +0,0 @@
|
||||
|
||||
(define-derived-mode carp-mode clojure-mode "Carp"
|
||||
"Major mode for the Carp programming language.")
|
||||
|
||||
(add-to-list 'auto-mode-alist '("\\.carp\\'" . carp-mode))
|
||||
|
||||
(provide 'carp-mode)
|
@ -1,635 +0,0 @@
|
||||
(require 'comint)
|
||||
(require 'thingatpt)
|
||||
|
||||
;; This code is blatantly stolen from clojure-inf by Bozhidar Batsov
|
||||
|
||||
(defgroup inf-carp nil
|
||||
"Run an external Carp process (REPL) in an Emacs buffer."
|
||||
:group 'carp)
|
||||
|
||||
(defcustom inf-carp-prompt-read-only t
|
||||
"If non-nil, the prompt will be read-only.
|
||||
|
||||
Also see the description of `ielm-prompt-read-only'."
|
||||
:type 'boolean
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-filter-regexp
|
||||
"\\`\\s *\\(:\\(\\w\\|\\s_\\)\\)?\\s *\\'"
|
||||
"What not to save on inferior Carp's input history.
|
||||
Input matching this regexp is not saved on the input history in Inferior Carp
|
||||
mode. Default is whitespace followed by 0 or 1 single-letter colon-keyword
|
||||
\(as in :a, :c, etc.)"
|
||||
:type 'regexp
|
||||
:group 'inf-carp)
|
||||
|
||||
(defvar inf-carp-mode-map
|
||||
(let ((map (copy-keymap comint-mode-map)))
|
||||
(define-key map "\C-x\C-e" #'inf-carp-eval-last-sexp)
|
||||
(define-key map "\C-c\C-l" #'inf-carp-load-file)
|
||||
(define-key map "\C-c\M-o" #'inf-carp-clear-repl-buffer)
|
||||
(easy-menu-define inf-carp-mode-menu map
|
||||
"Inferior Carp REPL Menu"
|
||||
'("Inf-Carp REPL"
|
||||
["Eval last sexp" inf-carp-eval-last-sexp t]
|
||||
"--"
|
||||
["Load file" inf-carp-load-file t]
|
||||
"--"
|
||||
["Show arglist" inf-carp-show-arglist t]
|
||||
;;["Show documentation for var" inf-carp-show-var-documentation t]
|
||||
;;["Show info for var" inf-carp-show-var-info t]
|
||||
"--"
|
||||
["Clear REPL" inf-carp-clear-repl-buffer]))
|
||||
map))
|
||||
|
||||
(defvar inf-carp-minor-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "\M-\C-x" #'inf-carp-eval-defun)
|
||||
(define-key map "\C-x\C-e" #'inf-carp-eval-last-sexp)
|
||||
(define-key map "\C-c\C-e" #'inf-carp-eval-last-sexp)
|
||||
(define-key map "\C-c\C-c" #'inf-carp-build-and-run)
|
||||
(define-key map (kbd "<s-return>") #'inf-carp-eval-defun)
|
||||
(define-key map "\C-c\C-k" #'inf-carp-build)
|
||||
(define-key map "\C-c\C-r" #'inf-carp-eval-region)
|
||||
(define-key map "\C-c\C-n" #'inf-carp-eval-form-and-next)
|
||||
(define-key map "\C-c\C-z" #'inf-carp-switch-to-repl)
|
||||
(define-key map "\C-c\C-m" #'inf-carp-macroexpand)
|
||||
(define-key map "\C-c\C-l" #'inf-carp-eval-buffer)
|
||||
;; TODO:
|
||||
;; (define-key map "\C-c\C-v" #'inf-carp-show-var-documentation)
|
||||
;; (define-key map "\C-c\C-t" #'inf-carp-show-var-type)
|
||||
|
||||
(easy-menu-define inf-carp-minor-mode-menu map
|
||||
"Inferior Carp Minor Mode Menu"
|
||||
'("Inf-Carp"
|
||||
["Eval top-level sexp at point" inf-carp-eval-defun t]
|
||||
["Eval last sexp" inf-carp-eval-last-sexp t]
|
||||
["Eval region" inf-carp-eval-region t]
|
||||
["Eval buffer" inf-carp-eval-buffer t]
|
||||
"--"
|
||||
["Load file..." inf-carp-load-file t]
|
||||
"--"
|
||||
["Switch to REPL" inf-carp-switch-to-repl t]
|
||||
["Set REPL ns" inf-carp-set-ns t]
|
||||
"--"
|
||||
;;["Show documentation for var" inf-carp-show-var-documentation t]
|
||||
["Macroexpand" inf-carp-macroexpand t]))
|
||||
map))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode inf-carp-minor-mode
|
||||
"Minor mode for interacting with the inferior Carp process buffer.
|
||||
|
||||
The following commands are available:
|
||||
|
||||
\\{inf-carp-minor-mode-map}"
|
||||
:lighter "" :keymap inf-carp-minor-mode-map)
|
||||
|
||||
(defcustom inf-carp-program "carp"
|
||||
"Program name for invoking an inferior Carp in Inferior Carp mode."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-load-command "(load \"%s\")\n"
|
||||
"Format-string for building a Carp expression to load a file.
|
||||
This format string should use `%s' to substitute a file name
|
||||
and should result in a Carp expression that will command the inferior Carp
|
||||
to load that file."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-prompt "^[^鲮 \n] *" ;; "^[^λ> \n]+λ> *"
|
||||
"Regexp to recognize prompts in the Inferior Carp mode."
|
||||
:type 'regexp
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-subprompt " *_> *"
|
||||
"Regexp to recognize subprompts in the Inferior Carp mode."
|
||||
:type 'regexp
|
||||
:group 'inf-carp)
|
||||
|
||||
(defvar inf-carp-buffer nil
|
||||
"The current inf-carp process buffer.
|
||||
|
||||
MULTIPLE PROCESS SUPPORT
|
||||
===========================================================================
|
||||
To run multiple Carp processes, you start the first up
|
||||
with \\[inf-carp]. It will be in a buffer named `*inf-carp*'.
|
||||
Rename this buffer with \\[rename-buffer]. You may now start up a new
|
||||
process with another \\[inf-carp]. It will be in a new buffer,
|
||||
named `*inf-carp*'. You can switch between the different process
|
||||
buffers with \\[switch-to-buffer].
|
||||
|
||||
Commands that send text from source buffers to Carp processes --
|
||||
like `inf-carp-eval-defun' or `inf-carp-show-arglist' -- have to choose a
|
||||
process to send to, when you have more than one Carp process around. This
|
||||
is determined by the global variable `inf-carp-buffer'. Suppose you
|
||||
have three inferior Carps running:
|
||||
Buffer Process
|
||||
foo inf-carp
|
||||
bar inf-carp<2>
|
||||
*inf-carp* inf-carp<3>
|
||||
If you do a \\[inf-carp-eval-defun] command on some Carp source code,
|
||||
what process do you send it to?
|
||||
|
||||
- If you're in a process buffer (foo, bar, or *inf-carp*),
|
||||
you send it to that process.
|
||||
- If you're in some other buffer (e.g., a source file), you
|
||||
send it to the process attached to buffer `inf-carp-buffer'.
|
||||
This process selection is performed by function `inf-carp-proc'.
|
||||
|
||||
Whenever \\[inf-carp] fires up a new process, it resets
|
||||
`inf-carp-buffer' to be the new process's buffer. If you only run
|
||||
one process, this does the right thing. If you run multiple
|
||||
processes, you might need to change `inf-carp-buffer' to
|
||||
whichever process buffer you want to use.")
|
||||
|
||||
(defvar inf-carp-mode-hook '()
|
||||
"Hook for customizing Inferior Carp mode.")
|
||||
|
||||
(put 'inf-carp-mode 'mode-class 'special)
|
||||
|
||||
(define-derived-mode inf-carp-mode comint-mode "Inferior Carp"
|
||||
"Major mode for interacting with an inferior Carp process.
|
||||
Runs a Carp interpreter as a subprocess of Emacs, with Carp I/O through an
|
||||
Emacs buffer. Variable `inf-carp-program' controls which Carp interpreter
|
||||
is run. Variables `inf-carp-prompt', `inf-carp-filter-regexp' and
|
||||
`inf-carp-load-command' can customize this mode for different Carp
|
||||
interpreters.
|
||||
|
||||
For information on running multiple processes in multiple buffers, see
|
||||
documentation for variable `inf-carp-buffer'.
|
||||
|
||||
\\{inf-carp-mode-map}
|
||||
|
||||
Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
|
||||
`inf-carp-mode-hook' (in that order).
|
||||
|
||||
You can send text to the inferior Carp process from other buffers containing
|
||||
Carp source.
|
||||
`inf-carp-switch-to-repl' switches the current buffer to the Carp process buffer.
|
||||
`inf-carp-eval-defun' sends the current defun to the Carp process.
|
||||
`inf-carp-eval-region' sends the current region to the Carp process.
|
||||
|
||||
Prefixing the inf-carp-eval/defun/region commands with
|
||||
a \\[universal-argument] causes a switch to the Carp process buffer after sending
|
||||
the text.
|
||||
|
||||
Commands:\\<inf-carp-mode-map>
|
||||
\\[comint-send-input] after the end of the process' output sends the text from the
|
||||
end of process to point.
|
||||
\\[comint-send-input] before the end of the process' output copies the sexp ending at point
|
||||
to the end of the process' output, and sends it.
|
||||
\\[comint-copy-old-input] copies the sexp ending at point to the end of the process' output,
|
||||
allowing you to edit it before sending it.
|
||||
If `comint-use-prompt-regexp' is nil (the default), \\[comint-insert-input] on old input
|
||||
copies the entire old input to the end of the process' output, allowing
|
||||
you to edit it before sending it. When not used on old input, or if
|
||||
`comint-use-prompt-regexp' is non-nil, \\[comint-insert-input] behaves according to
|
||||
its global binding.
|
||||
\\[backward-delete-char-untabify] converts tabs to spaces as it moves back.
|
||||
\\[carp-indent-line] indents for Carp; with argument, shifts rest
|
||||
of expression rigidly with the current line.
|
||||
\\[indent-sexp] does \\[carp-indent-line] on each line starting within following expression.
|
||||
Paragraphs are separated only by blank lines. Semicolons start comments.
|
||||
If you accidentally suspend your process, use \\[comint-continue-subjob]
|
||||
to continue it."
|
||||
(setq comint-prompt-regexp inf-carp-prompt)
|
||||
(setq mode-line-process '(":%s"))
|
||||
;;(carp-mode-variables) ;; ???
|
||||
;;(inf-carp-eldoc-setup)
|
||||
(setq comint-get-old-input #'inf-carp-get-old-input)
|
||||
(setq comint-input-filter #'inf-carp-input-filter)
|
||||
(set (make-local-variable 'comint-prompt-read-only) inf-carp-prompt-read-only)
|
||||
(add-hook 'comint-preoutput-filter-functions #'inf-carp-preoutput-filter nil t)
|
||||
(add-hook 'completion-at-point-functions #'inf-carp-completion-at-point nil t))
|
||||
|
||||
(add-hook 'carp-mode-hook (lambda () (inf-carp-minor-mode 1)))
|
||||
|
||||
(defun inf-carp-get-old-input ()
|
||||
"Return a string containing the sexp ending at point."
|
||||
(save-excursion
|
||||
(let ((end (point)))
|
||||
(backward-sexp)
|
||||
(buffer-substring (point) end))))
|
||||
|
||||
(defun inf-carp-input-filter (str)
|
||||
"Return t if STR does not match `inf-carp-filter-regexp'."
|
||||
(not (string-match inf-carp-filter-regexp str)))
|
||||
|
||||
(defun inf-carp-chomp (string)
|
||||
"Remove final newline from STRING."
|
||||
(if (string-match "[\n]\\'" string)
|
||||
(replace-match "" t t string)
|
||||
string))
|
||||
|
||||
(defun inf-carp-remove-subprompts (string)
|
||||
"Remove subprompts from STRING."
|
||||
(replace-regexp-in-string inf-carp-subprompt "" string))
|
||||
|
||||
(defun inf-carp-preoutput-filter (str)
|
||||
"Preprocess the output STR from interactive commands."
|
||||
(cond
|
||||
((string-prefix-p "inf-carp-" (symbol-name (or this-command last-command)))
|
||||
;; Remove subprompts and prepend a newline to the output string
|
||||
(inf-carp-chomp (concat "\n" (inf-carp-remove-subprompts str))))
|
||||
(t str)))
|
||||
|
||||
(defvar inf-carp-project-root-files
|
||||
'("project.carp")
|
||||
"A list of files that can be considered project markers.")
|
||||
|
||||
(defun inf-carp-project-root ()
|
||||
"Retrieve the root directory of a project if available.
|
||||
|
||||
Fallback to `default-directory.' if not within a project."
|
||||
(or (car (remove nil
|
||||
(mapcar (lambda
|
||||
(file)
|
||||
(locate-dominating-file default-directory file))
|
||||
inf-carp-project-root-files)))
|
||||
default-directory))
|
||||
|
||||
(defun inf-carp-clear-repl-buffer ()
|
||||
"Clear the REPL buffer."
|
||||
(interactive)
|
||||
(let ((comint-buffer-maximum-size 0))
|
||||
(comint-truncate-buffer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun inf-carp (cmd)
|
||||
"Run an inferior Carp process, input and output via buffer `*inf-carp*'.
|
||||
If there is a process already running in `*inf-carp*', just switch
|
||||
to that buffer.
|
||||
With argument, allows you to edit the command line (default is value
|
||||
of `inf-carp-program'). Runs the hooks from
|
||||
`inf-carp-mode-hook' (after the `comint-mode-hook' is run).
|
||||
\(Type \\[describe-mode] in the process buffer for a list of commands.)"
|
||||
(interactive (list (if current-prefix-arg
|
||||
(read-string "Run Carp: " inf-carp-program)
|
||||
inf-carp-program)))
|
||||
(if (not (comint-check-proc "*inf-carp*"))
|
||||
;; run the new process in the project's root when in a project folder
|
||||
(let ((default-directory (inf-carp-project-root))
|
||||
(cmdlist (split-string cmd)))
|
||||
(set-buffer (apply #'make-comint
|
||||
"inf-carp" (car cmdlist) nil (cdr cmdlist)))
|
||||
(inf-carp-mode)))
|
||||
(setq inf-carp-buffer "*inf-carp*")
|
||||
;;(split-window-below)
|
||||
;;(pop-to-buffer-same-window "*inf-carp*")
|
||||
(pop-to-buffer "*inf-carp*")
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'run-carp 'inf-carp)
|
||||
|
||||
(defun inf-carp-eval-region (start end &optional and-go)
|
||||
"Send the current region to the inferior Carp process.
|
||||
Prefix argument AND-GO means switch to the Carp buffer afterwards."
|
||||
(interactive "r\nP")
|
||||
;; replace multiple newlines at the end of the region by a single one
|
||||
;; or add one if there was no newline
|
||||
(let ((str (replace-regexp-in-string
|
||||
"[\n]*\\'" "\n"
|
||||
(buffer-substring-no-properties start end))))
|
||||
(comint-send-string (inf-carp-proc) str))
|
||||
(if and-go (inf-carp-switch-to-repl t)))
|
||||
|
||||
(defun inf-carp-eval-string (code)
|
||||
"Send the string CODE to the inferior Carp process to be executed."
|
||||
(comint-send-string (inf-carp-proc) (concat code "\n")))
|
||||
|
||||
(defun inf-carp-eval-defun (&optional and-go)
|
||||
"Send the current defun to the inferior Carp process.
|
||||
Prefix argument AND-GO means switch to the Carp buffer afterwards."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(end-of-defun)
|
||||
(let ((end (point)) (case-fold-search t))
|
||||
(beginning-of-defun)
|
||||
(inf-carp-eval-region (point) end and-go))))
|
||||
|
||||
(defun inf-carp-eval-buffer (&optional and-go)
|
||||
"Send the current buffer to the inferior Carp process.
|
||||
Prefix argument AND-GO means switch to the Carp buffer afterwards."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(widen)
|
||||
(let ((case-fold-search t))
|
||||
(inf-carp-eval-region (point-min) (point-max) and-go))))
|
||||
|
||||
(defun inf-carp-eval-last-sexp (&optional and-go)
|
||||
"Send the previous sexp to the inferior Carp process.
|
||||
Prefix argument AND-GO means switch to the Carp buffer afterwards."
|
||||
(interactive "P")
|
||||
(inf-carp-eval-region (save-excursion (backward-sexp) (point)) (point) and-go))
|
||||
|
||||
(defun inf-carp-eval-form-and-next ()
|
||||
"Send the previous sexp to the inferior Carp process and move to the next one."
|
||||
(interactive "")
|
||||
(while (not (zerop (car (syntax-ppss))))
|
||||
(up-list))
|
||||
(inf-carp-eval-last-sexp)
|
||||
(forward-sexp))
|
||||
|
||||
(defun inf-carp-switch-to-repl (eob-p)
|
||||
"Switch to the inferior Carp process buffer.
|
||||
With prefix argument EOB-P, positions cursor at end of buffer."
|
||||
(interactive "P")
|
||||
(if (get-buffer-process inf-carp-buffer)
|
||||
(let ((pop-up-frames
|
||||
;; Be willing to use another frame
|
||||
;; that already has the window in it.
|
||||
(or pop-up-frames
|
||||
(get-buffer-window inf-carp-buffer t))))
|
||||
(pop-to-buffer inf-carp-buffer))
|
||||
(run-carp inf-carp-program))
|
||||
(when eob-p
|
||||
(push-mark)
|
||||
(goto-char (point-max))))
|
||||
|
||||
|
||||
;;; Now that inf-carp-eval-/defun/region takes an optional prefix arg,
|
||||
;;; these commands are redundant. But they are kept around for the user
|
||||
;;; to bind if he wishes, for backwards functionality, and because it's
|
||||
;;; easier to type C-c e than C-u C-c C-e.
|
||||
|
||||
(defun inf-carp-eval-region-and-go (start end)
|
||||
"Send the current region to the inferior Carp, and switch to its buffer."
|
||||
(interactive "r")
|
||||
(inf-carp-eval-region start end t))
|
||||
|
||||
(defun inf-carp-eval-defun-and-go ()
|
||||
"Send the current defun to the inferior Carp, and switch to its buffer."
|
||||
(interactive)
|
||||
(inf-carp-eval-defun t))
|
||||
|
||||
(defvar inf-carp-prev-l/c-dir/file nil
|
||||
"Record last directory and file used in loading or compiling.
|
||||
This holds a cons cell of the form `(DIRECTORY . FILE)'
|
||||
describing the last `inf-carp-load-file' command.")
|
||||
|
||||
(defcustom inf-carp-source-modes '(carp-mode)
|
||||
"Used to determine if a buffer contains Carp source code.
|
||||
If it's loaded into a buffer that is in one of these major modes, it's
|
||||
considered a Carp source file by `inf-carp-load-file'.
|
||||
Used by this command to determine defaults."
|
||||
:type '(repeat symbol)
|
||||
:group 'inf-carp)
|
||||
|
||||
(defun inf-carp-load-file (file-name)
|
||||
"Load a Carp file FILE-NAME into the inferior Carp process."
|
||||
(interactive (comint-get-source "Load Carp file: " inf-carp-prev-l/c-dir/file
|
||||
inf-carp-source-modes nil)) ; nil because LOAD
|
||||
; doesn't need an exact name
|
||||
(comint-check-source file-name) ; Check to see if buffer needs saved.
|
||||
(setq inf-carp-prev-l/c-dir/file (cons (file-name-directory file-name)
|
||||
(file-name-nondirectory file-name)))
|
||||
(comint-send-string (inf-carp-proc)
|
||||
(format inf-carp-load-command file-name))
|
||||
(inf-carp-switch-to-repl t))
|
||||
|
||||
(defun inf-carp-connected-p ()
|
||||
"Return t if inferior Carp is currently connected, nil otherwise."
|
||||
(not (null inf-carp-buffer)))
|
||||
|
||||
|
||||
;;; Documentation functions: function doc, var doc, arglist, and
|
||||
;;; describe symbol.
|
||||
;;; ===========================================================================
|
||||
|
||||
;;; Command strings
|
||||
;;; ===============
|
||||
|
||||
(defcustom inf-carp-build-command
|
||||
"(do (reload) (build))\n"
|
||||
"Command to build the project."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-build-and-run-command
|
||||
"(do (reload) (build) (run))\n"
|
||||
"Command to build and run the project."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-var-type-command
|
||||
"(type %s)\n"
|
||||
"Command to query inferior Carp for a var's type."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-var-info-command
|
||||
"(info %s)\n"
|
||||
"Command to query inferior Carp for a var's source."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-arglist-command
|
||||
"(try
|
||||
(:arglists
|
||||
(carp.core/meta
|
||||
(carp.core/resolve
|
||||
(carp.core/read-string \"%s\"))))
|
||||
(catch Throwable t nil))\n"
|
||||
"Command to query inferior Carp for a function's arglist."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-completion-command
|
||||
"(complete.core/completions \"%s\")\n"
|
||||
"Command to query inferior Carp for completion candidates."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
(defcustom inf-carp-macroexpand-command
|
||||
"(expand '%s)\n"
|
||||
"Command to invoke macroexpand."
|
||||
:type 'string
|
||||
:group 'inf-carp)
|
||||
|
||||
;;; Ancillary functions
|
||||
;;; ===================
|
||||
|
||||
;;; Reads a string from the user.
|
||||
(defun inf-carp-symprompt (prompt default)
|
||||
(list (let* ((prompt (if default
|
||||
(format "%s (default %s): " prompt default)
|
||||
(concat prompt ": ")))
|
||||
(ans (read-string prompt)))
|
||||
(if (zerop (length ans)) default ans))))
|
||||
|
||||
|
||||
;;; Adapted from function-called-at-point in help.el.
|
||||
(defun inf-carp-fn-called-at-pt ()
|
||||
"Return the name of the function called in the current call.
|
||||
The value is nil if it can't find one."
|
||||
(condition-case nil
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(narrow-to-region (max (point-min) (- (point) 1000)) (point-max))
|
||||
(backward-up-list 1)
|
||||
(forward-char 1)
|
||||
(let ((obj (read (current-buffer))))
|
||||
(and (symbolp obj) obj))))
|
||||
(error nil)))
|
||||
|
||||
|
||||
;;; Adapted from variable-at-point in help.el.
|
||||
(defun inf-carp-var-at-pt ()
|
||||
(condition-case ()
|
||||
(save-excursion
|
||||
(forward-sexp -1)
|
||||
(skip-chars-forward "'")
|
||||
(let ((obj (read (current-buffer))))
|
||||
(and (symbolp obj) obj)))
|
||||
(error nil)))
|
||||
|
||||
(defun inf-carp-symbol-at-point ()
|
||||
"Return the name of the symbol at point, otherwise nil."
|
||||
(or (thing-at-point 'symbol) ""))
|
||||
|
||||
(defun inf-carp-build ()
|
||||
"Send a command to the inferior Carp to build a form.
|
||||
See variable `inf-carp-var-build-command'."
|
||||
(interactive)
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-build-command)))
|
||||
|
||||
(defun inf-carp-build-and-run ()
|
||||
"Send a command to the inferior Carp to build a form.
|
||||
See variable `inf-carp-var-build-command'."
|
||||
(interactive)
|
||||
(inf-carp-eval-buffer)
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-build-and-run-command)))
|
||||
|
||||
(defun inf-carp-bake (var)
|
||||
"Send a command to the inferior Carp to bake a form.
|
||||
See variable `inf-carp-var-bake-command'."
|
||||
(interactive (inf-carp-symprompt "Var bake" (inf-carp-var-at-pt)))
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-var-bake-command var)))
|
||||
|
||||
;;; Documentation functions: var doc and arglist.
|
||||
;;; ======================================================================
|
||||
|
||||
(defun inf-carp-show-var-type (var)
|
||||
"Send a command to the inferior Carp to give type for VAR.
|
||||
See variable `inf-carp-var-type-command'."
|
||||
(interactive (inf-carp-symprompt "Var type" (inf-carp-var-at-pt)))
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-var-type-command var)))
|
||||
|
||||
(defun inf-carp-arglist (fn)
|
||||
"Send a query to the inferior Carp for the arglist for function FN.
|
||||
See variable `inf-carp-arglist-command'."
|
||||
(interactive (inf-carp-symprompt "Arglist" (inf-carp-fn-called-at-pt)))
|
||||
(let* ((proc (inf-carp-proc))
|
||||
(comint-filt (process-filter proc))
|
||||
(kept "")
|
||||
eldoc)
|
||||
(set-process-filter proc (lambda (_proc string) (setq kept (concat kept string))))
|
||||
(unwind-protect
|
||||
(let ((eldoc-snippet (format inf-carp-arglist-command fn)))
|
||||
(process-send-string proc eldoc-snippet)
|
||||
(while (and (not (string-match inf-carp-prompt kept))
|
||||
(accept-process-output proc 2)))
|
||||
(setq eldoc (and (string-match "(.+)" kept) (match-string 0 kept)))
|
||||
)
|
||||
(set-process-filter proc comint-filt))
|
||||
eldoc))
|
||||
|
||||
(defun inf-carp-show-arglist (fn)
|
||||
"Show the arglist for function FN in the mini-buffer."
|
||||
(interactive (inf-carp-symprompt "Arglist" (inf-carp-fn-called-at-pt)))
|
||||
(let ((eldoc (inf-carp-arglist fn)))
|
||||
(when eldoc
|
||||
(message "%s: %s" fn eldoc))))
|
||||
|
||||
(defun inf-carp-show-ns-vars (ns)
|
||||
"Send a query to the inferior Carp for the public vars in NS.
|
||||
See variable `inf-carp-ns-vars-command'."
|
||||
(interactive (inf-carp-symprompt "Ns vars" (carp-find-ns)))
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-ns-vars-command ns)))
|
||||
|
||||
(defun inf-carp-set-ns (ns)
|
||||
"Set the ns of the inferior Carp process to NS.
|
||||
Defaults to the ns of the current buffer."
|
||||
(interactive (inf-carp-symprompt "Set ns to" (carp-find-ns)))
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-set-ns-command ns)))
|
||||
|
||||
(defun inf-carp-apropos (var)
|
||||
"Send a command to the inferior Carp to give apropos for VAR.
|
||||
See variable `inf-carp-apropos-command'."
|
||||
(interactive (inf-carp-symprompt "Var apropos" (inf-carp-var-at-pt)))
|
||||
(comint-proc-query (inf-carp-proc) (format inf-carp-apropos-command var)))
|
||||
|
||||
(defun inf-carp-macroexpand (&optional macro-1)
|
||||
"Send a command to the inferior Carp to give apropos for VAR.
|
||||
See variable `inf-carp-macroexpand-command'.
|
||||
With a prefix arg MACRO-1 uses `inf-carp-macroexpand-1-command'."
|
||||
(interactive "P")
|
||||
(let ((last-sexp (buffer-substring-no-properties (save-excursion (backward-sexp) (point)) (point))))
|
||||
(comint-send-string
|
||||
(inf-carp-proc)
|
||||
(format (if macro-1
|
||||
inf-carp-macroexpand-1-command
|
||||
inf-carp-macroexpand-command)
|
||||
last-sexp))))
|
||||
|
||||
|
||||
(defun inf-carp-proc ()
|
||||
"Return the current inferior Carp process.
|
||||
See variable `inf-carp-buffer'."
|
||||
(let ((proc (get-buffer-process (if (derived-mode-p 'inf-carp-mode)
|
||||
(current-buffer)
|
||||
inf-carp-buffer))))
|
||||
(or proc
|
||||
(error "No Carp subprocess; see variable `inf-carp-buffer'"))))
|
||||
|
||||
(defun inf-carp-completions (expr)
|
||||
"Return a list of completions for the Carp expression starting with EXPR."
|
||||
(let* ((proc (inf-carp-proc))
|
||||
(comint-filt (process-filter proc))
|
||||
(kept "")
|
||||
completions)
|
||||
(set-process-filter proc (lambda (_proc string) (setq kept (concat kept string))))
|
||||
(unwind-protect
|
||||
(let ((completion-snippet
|
||||
(format
|
||||
inf-carp-completion-command (substring-no-properties expr))))
|
||||
(process-send-string proc completion-snippet)
|
||||
(while (and (not (string-match inf-carp-prompt kept))
|
||||
(accept-process-output proc 2)))
|
||||
(setq completions (read kept))
|
||||
;; Subprocess echoes output on Windows and OS X.
|
||||
(when (and completions (string= (concat (car completions) "\n") completion-snippet))
|
||||
(setq completions (cdr completions))))
|
||||
(set-process-filter proc comint-filt))
|
||||
completions))
|
||||
|
||||
(defconst inf-carp-carp-expr-break-chars " \t\n\"\'`><,;|&{(")
|
||||
|
||||
(defun inf-carp-completion-bounds-of-expr-at-point ()
|
||||
"Return bounds of expression at point to complete."
|
||||
(when (not (memq (char-syntax (following-char)) '(?w ?_)))
|
||||
(save-excursion
|
||||
(let ((end (point)))
|
||||
(skip-chars-backward (concat "^" inf-carp-carp-expr-break-chars))
|
||||
(cons (point) end)))))
|
||||
|
||||
(defun inf-carp-completion-expr-at-point ()
|
||||
"Return expression at point to complete."
|
||||
(let ((bounds (inf-carp-completion-bounds-of-expr-at-point)))
|
||||
(and bounds
|
||||
(buffer-substring (car bounds) (cdr bounds)))))
|
||||
|
||||
(defun inf-carp-completion-at-point ()
|
||||
"Retrieve the list of completions and prompt the user.
|
||||
Returns the selected completion or nil."
|
||||
(let ((bounds (inf-carp-completion-bounds-of-expr-at-point)))
|
||||
(when bounds
|
||||
(list (car bounds) (cdr bounds)
|
||||
(if (fboundp 'completion-table-with-cache)
|
||||
(completion-table-with-cache #'inf-carp-completions)
|
||||
(completion-table-dynamic #'inf-carp-completions))))))
|
||||
|
||||
(provide 'inf-carp-mode)
|
Loading…
Reference in New Issue
Block a user