0

I'm trying to get command and file tab completion to work in telnet-mode.

For that, I did bind the TAB key to completion-at-point in telnet-mode-map. The function is called as expected but it does not work properly (not providing the completion list and printing erratically).

The completion-at-point works fine shell-mode for instance.
Is it possible to get it working properly under telnet-mode?

5
  • telnet.el does not support completion. But you can abbreviate telnet commands. A unique start string of the command is sufficient to call the command.
    – Tobias
    May 23, 2022 at 10:25
  • @Tobias do you think it would be possible to add telnet completion support to telnet.el? Is there something that would prevent it?
    – PRouleau
    May 24, 2022 at 19:31
  • Are you github.com/PRouleau ? Interested in setting up a Git repo?
    – Tobias
    May 25, 2022 at 11:39
  • Note, that is me: github.com/TobiasZawada I am not as experienced as Drew or MilkyPostMan, but I have at least some experience in setting up packages. So I could help you. But, I cannot maintain packages that I am not really using. Pityingly, the original author of telnet William F. Schelter passed away. But, if we want to get completion for telnet working we need some help from the maintainers (i.e., pityingly, [email protected]) to fix some issues in telnet.el.
    – Tobias
    May 25, 2022 at 11:49
  • Thanks @Tobias, I'll look into it later, and will try to get it going in a clone of the file first. I don't have time now but will try later when I get time. I have to use telnet sometimes for local testing of embedded systems where telnet is activated for engineering testing only and where ssh is not available.
    – PRouleau
    May 25, 2022 at 18:39

1 Answer 1

1

telnet-mode is not prepared for completion.
The following code shows how you can add completion support with the help of pcomplete.

I don't use telnet. So the code is certainly broken.
Use the code just as a general direction of how you can add completion. I think you will need some support from the maintainer of telnet.el to fix the little bugs in the code.

Note, that only some example telnet commands are implemented.
You need to complete the set of commands pcomplete/telnet-mode/COMMAND yourself.

(require 'telnet)
(require 'pcomplete)

;; Somehow `telnet-send-input' messes up the promopt.
;; Pressing RET repeately causes multiple prompts on one line.
;; With multiple prompts on one line `pcomplete' does no longer recognize commands.
;; The following fixes that problem for `pcomplete'
;; but it certainly breaks something in `telnet'.
;; That needs to be cleared with the maintainer of the package.
(advice-add 'telnet-send-input :override #'comint-send-input)

(defconst telnetTZA-commands
  '("auth"
    "close"
    "display"
    "encrypt"
    "environ"
    "logout"
    "mode"
    "open"
    "quit"
    "send"
    "set"
    "unset"
    "slc"
    "toggle"
    "z"
    "!"
    "?"
    )
  "List of telnet commands according to the Man page of telnet.")

(defun telnetTZA-pcomplete-command ()
  "Complete telnet command."
  (pcomplete-here
   telnetTZA-commands))

(defun telnetTZA-pcomplete-setup ()
  "Setup pcomplete for `telnet-mode'."
  (setq-local pcomplete-command-completion-function #'telnetTZA-pcomplete-command)
  (local-set-key [tab] #'completion-at-point)
  (pcomplete-comint-setup 'comint-dynamic-complete-functions))

(add-hook 'telnet-mode-hook #'telnetTZA-pcomplete-setup)

;; `comint-run-thing-process' is just a helper. We move its definition behind the essential stuff.
(declare-function #'comint-run-thing-process load-file-name)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Completion of commands in `telnet-mode':

(defun pcomplete/telnet-mode/auth ()
  "Complete args of \"auth\" command in `telnet-mode'."
  ;; first argument
  (pcomplete-here
   '("disable" "enable" "status"))
  ;; second argument
  (pcomplete-here
   (pcase (pcomplete-arg 1)
     ("disable"
      (telnetTZA-completion-from-help "disable ?"))
     ("enable"
      (telnetTZA-completion-from-help "enable ?")))))

(defun pcomplete/telnet-mode/environ ()
  "Complete args of \"environ\" command in `telnet-mode'."
  ;; first arg
  (pcomplete-here
   '("define" "undefine" "export" "unexport" "send" "list" "?"))
  ;; second arg
  (pcomplete-here
   (when (member (pcomplete-arg 1) '("undefine" "export" "unexport" "send"))
     (telnetTZA-completion-from-help "environ list"))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Helpers:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; `comint-run-thing-process' is stolen from https://stackoverflow.com/questions/46631920/silently-send-command-to-comint-without-printing-prompt.
;; There is also needed some work here.
(defun comint-run-thing-process (process command)
  "Send COMMAND to PROCESS."
  (let ((output-buffer " *Comint Redirect Work Buffer*"))
    (with-current-buffer (get-buffer-create output-buffer)
      (erase-buffer)
      (comint-redirect-send-command-to-process command
                                               output-buffer process nil t)
      ;; Wait for the process to complete
      (set-buffer (process-buffer process))
      (while (and (null comint-redirect-completed)
                  (accept-process-output process)))
      ;; Collect the output
      (set-buffer output-buffer)
      (goto-char (point-min))
      ;; Skip past the command, if it was echoed
      (and (looking-at command)
           (forward-line))
      ;; Grab the rest of the buffer
      (buffer-substring-no-properties (point) (- (point-max) 1)))))

(defun telnetTZA-completion-from-help (command)
  "Run COMMAND in telnet buffer and collect first word for each line."
  (let* ((output (comint-run-thing-process (get-buffer-process (current-buffer)) command))
     (lines (split-string output "\n"))
     (words (seq-remove
         #'string-empty-p
         (mapcar
          (lambda (str)
            (setq str (string-trim-left str))
            (string-trim-right str "[[:space:]].*"))
          lines))))
    words))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.