1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
;;; company-matlab-shell.el --- a matlab-shell-mode completion back-end for MATLAB -*- lexical-binding: t -*-
;; Copyright (C) 2024 Free Software Foundation, Inc.
;; Author: Eric Ludlam <zappo@gnu.org>
;; David Engster <dengste@eml.cc>
;;
;; 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.
;;
;; 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.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(condition-case nil
(require 'company)
(error nil))
(require 'cl-macs)
(require 'matlab)
(require 'matlab-shell)
(defvar company-matlab-shell--ci (make-hash-table :test 'equal)
"Private variable for `company-matlab-shell' completion info.")
(defun company-matlab-shell-grab-completion-substr ()
"Return the completion substring of the command.
The completion substring is to be completed in `matlab-shell', or
\\='stop if completions can't be performed at the current point."
(when (eq major-mode 'matlab-shell-mode)
(if (not (matlab-on-prompt-p))
'stop ;; tell company can't complete when point is not in the prompt
(let ((lastcmd (buffer-substring (point) (line-end-position))))
;; Kill the rest of the line since completion only works at the end of the line and
;; we'd like it to complete within a line. For example,
;; h=figure;
;; h.set('Vis','on')
;; ^
;; TAB here results in:
;; h.set('Visible','on')
(delete-region (point) (line-end-position))
(let* ((buf-name (buffer-name (current-buffer)))
(ci (matlab-shell-get-completion-info))
(common-substr (cdr (assoc 'common-substr ci)))
(did-completion (cdr (assoc 'did-completion ci))))
;; restore the killed part of the line
(let ((orig-pt (point)))
(insert lastcmd)
(goto-char orig-pt))
;; If did-completion, then matlab-shell-get-completion-info updated the
;; *MATLAB* buffer by deleting text and calling (insert replacement-text), and
;; we have no more completion info.
(if did-completion
;; Tell company to abort completion. This causes "Cannot complete at point" and
;; there doesn't seem to be a way to protect against this message.
nil
(puthash buf-name ci company-matlab-shell--ci)
;; command to be completed
common-substr
))))))
(defun company-matlab-shell-get-completions ()
"Get matlab-shell completions."
(let* ((ci (if (eq major-mode 'matlab-shell-mode)
(gethash (buffer-name (current-buffer)) company-matlab-shell--ci)))
(completions (if ci (cdr (assoc 'completions ci)))))
(if ci (remhash (buffer-name (current-buffer)) company-matlab-shell--ci))
(mapcar 'car completions)))
;;;###autoload
(defun company-matlab-shell (command &optional arg &rest ignored)
"A `company-mode' completion backend for `matlab-shell'.
COMMAND is the item to complete.
ARG and IGNORED are ignored."
(interactive (list 'interactive))
(ignore arg ignored)
(cl-case command
( interactive (if (fboundp 'company-begin-backend) ;; quiet warning when no company
(company-begin-backend 'company-matlab-shell)
(error "Unable to provide completions - company-begin-backend is missing")))
( prefix (company-matlab-shell-grab-completion-substr))
( candidates (company-matlab-shell-get-completions))
( sorted t)))
(provide 'company-matlab-shell)
;;; company-matlab-shell.el ends here
;; LocalWords: Ludlam Engster ci defun substr lastcmd eol buf cdr puthash gethash remhash mapcar
;; LocalWords: fboundp
|