Last active
September 30, 2016 20:32
-
-
Save nealey/e7b3eb06fc1f7a31d76f142ea5a1e6c8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; | |
;; ssh | |
;; | |
(require 'comint) | |
(require 'shell) | |
(defgroup ssh nil | |
"Secure shell interface" | |
:group 'processes | |
:group 'unix) | |
(defcustom ssh-program (if (eq system-type 'windows-nt) "plink" "ssh") | |
"*Name of program to invoke SSH" | |
:type 'string | |
:group 'ssh) | |
(defcustom ssh-explicit-args '() | |
"*List of arguments to pass to ssh on the command line." | |
:type '(repeat (string :tag "Argument")) | |
:group 'ssh) | |
(defcustom ssh-default-host nil | |
"*Default hostname (the one you go to the most frequently)" | |
:type 'string | |
:group 'ssh) | |
(defcustom ssh-frequent-hosts '() | |
"*Hosts to pre-populate history" | |
:type '(repeat (string :tag "Host")) | |
:group 'ssh) | |
(defvar ssh-mode-map '()) | |
(cond | |
((null ssh-mode-map) | |
(setq ssh-mode-map (if (consp shell-mode-map) | |
(cons 'keymap shell-mode-map) | |
(copy-keymap shell-mode-map))) | |
(define-key ssh-mode-map "\C-c\C-c" 'ssh-send-Ctrl-C) | |
(define-key ssh-mode-map "\C-c\C-d" 'ssh-send-Ctrl-D) | |
(define-key ssh-mode-map "\C-c\C-z" 'ssh-send-Ctrl-Z) | |
(define-key ssh-mode-map "\C-c\C-\\" 'ssh-send-Ctrl-backslash) | |
(define-key ssh-mode-map "\C-d" 'ssh-delchar-or-send-Ctrl-D) | |
(define-key ssh-mode-map "\C-i" 'ssh-tab-or-complete))) | |
(defun ssh-known-hosts () | |
"Return a list of hosts for completion" | |
(if (file-readable-p "~/.ssh/known_hosts") | |
(with-temp-buffer | |
(insert-file-contents-literally "~/.ssh/known_hosts") | |
(let ((ssh-hosts-list) '()) | |
(while (not (eobp)) | |
(add-to-list 'ssh-hosts-list (buffer-substring (point) (- (search-forward-regexp "[, ]") 1))) | |
(forward-line)) | |
ssh-hosts-list)) | |
'())) | |
(defvar ssh-host-history nil) | |
(defvar ssh-remote nil) | |
(defun ssh (remote) | |
(interactive | |
(list | |
(completing-read (format "Remote host (default %s): " ssh-default-host) | |
(append ssh-frequent-hosts (ssh-known-hosts)) | |
nil nil "" 'ssh-host-history))) | |
(if (string= remote "") | |
(setq remote ssh-default-host)) | |
(let* ((buffer-name (generate-new-buffer-name (format "*ssh %s*" remote))) | |
(buffer (get-buffer-create buffer-name)) | |
(process-connection-type t) | |
(default-directory "/tmp") | |
(args (append ssh-explicit-args (list remote)))) | |
(pop-to-buffer buffer) | |
(with-current-buffer buffer | |
(comint-exec buffer buffer-name ssh-program nil args) | |
(ssh-mode) | |
(setq-local ssh-remote remote) | |
(setq-local dabbrev-abbrev-char-regexp "\\sw\\|\\s_\\|[-._,]") | |
(cond | |
((string-match "\.ilo$" remote) | |
(setq-local comint-input-sender 'ssh-comint-cr-send)) | |
((string-equal ssh-program "plink") | |
(setq-local comint-input-sender 'ssh-comint-plink-send)))))) | |
(global-set-key (kbd "C-c s") 'ssh) | |
(put 'ssh-mode 'mode-class 'special) | |
(defun ssh-mode () | |
"Set major-mode for ssh sessions." | |
(interactive) | |
(kill-all-local-variables) | |
(shell-mode) | |
(setq major-mode 'ssh-mode) | |
(setq mode-name "ssh") | |
(use-local-map ssh-mode-map) | |
(run-hooks 'ssh-mode-hook)) | |
;; | |
;; Kill old buffers; not sure this is a fantastic idea | |
;; | |
(defun ssh/shell-kill-buffer-sentinel (process event) | |
(when (memq (process-status process) '(exit signal)) | |
(kill-buffer (process-buffer process)))) | |
(defun ssh/kill-process-buffer-on-exit () | |
(set-process-sentinel (get-buffer-process (current-buffer)) | |
#'ssh/shell-kill-buffer-sentinel)) | |
(add-hook 'comint-exec-hook 'ssh/kill-process-buffer-on-exit) | |
(defun ssh-comint-send-line (proc string newline) | |
"Send a string terminated by `newline` (if appropriate)" | |
(let ((send-string | |
(if comint-input-sender-no-newline | |
string | |
(concat string newline)))) | |
(comint-send-string proc send-string)) | |
(if (and comint-input-sender-no-newline | |
(not (string-equal string ""))) | |
(process-send-eof))) | |
(defun ssh-comint-cr-send (proc string) | |
"Send a comint string terminated with carriage return | |
Some machines (HP iLO) need this, because reasons." | |
(ssh-comint-send-line proc string "\r")) | |
(defun ssh-comint-plink-send (proc string) | |
"Send a string to plink | |
Plink wants \\n when it asks for a password, | |
but if you send \\n in a session, that winds up being two \\n on the server, | |
so you have to send \\r. | |
This is very strange." | |
(let ((newline "\r")) | |
(with-current-buffer (process-buffer proc) | |
;; Maybe there's a better way to do this :( | |
(when (< (count-lines (point-min) (point-max)) 8) | |
(message "Sending \\n instead of \\r since the buffer is small...") | |
(setq newline "\n"))) | |
(ssh-comint-send-line proc string newline))) | |
(provide 'ssh) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment