You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
9.9 KiB
327 lines
9.9 KiB
;;; ssh-config-mode.el --- Mode for fontification of ~/.ssh/config
|
|
;;
|
|
;; ssh-config-mode-el/ssh-config-mode.el ---
|
|
;;
|
|
;; $Id: ssh-config-mode.el,v 1.14 2012/05/14 05:29:26 harley Exp $
|
|
;;
|
|
|
|
;; Author: Harley Gorrell <harley@panix.com>
|
|
;; URL: https://github.com/jhgorrell/ssh-config-mode-el
|
|
;; Github: https://raw.github.com/jhgorrell/ssh-config-mode-el/master/ssh-config-mode.el
|
|
;; License: GPL v3+ (https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
;; Keywords: ssh, config, emacs
|
|
;; Version: $Revision: 1.14 $
|
|
;; Tag: 20170413T0010
|
|
|
|
;;; Commentary:
|
|
;; * Fontifys the ssh config keywords.
|
|
;; * keys for skipping from host section to host section.
|
|
;; * Add the following to your startup file.
|
|
;; (autoload 'ssh-config-mode "ssh-config-mode" t)
|
|
;; (add-to-list 'auto-mode-alist '("/\\.ssh/config\\'" . ssh-config-mode))
|
|
;; (add-to-list 'auto-mode-alist '("/sshd?_config\\'" . ssh-config-mode))
|
|
;; (add-to-list 'auto-mode-alist '("/knownhosts\\'" . ssh-known-hosts-mode))
|
|
;; (add-to-list 'auto-mode-alist '("/authorized_keys2?\\'" . ssh-authorized-keys-mode))
|
|
;; (add-hook 'ssh-config-mode-hook 'turn-on-font-lock)
|
|
|
|
;;; History:
|
|
;; * This keeps checkdoc happy.
|
|
|
|
;;; License
|
|
;;
|
|
;; This file 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, or (at your option)
|
|
;; any later version.
|
|
|
|
;; This file 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/>.
|
|
|
|
;;; Code:
|
|
;; (eval-buffer)
|
|
;; (progn (delete-trailing-whitespace) (indent-region 0 (point-max)))
|
|
;; (byte-compile-file "ssh-config-mode.el" t)
|
|
;; (load "ssh-config-mode")
|
|
|
|
;; We use eval-and-compile so we can use them at compile
|
|
;; time and call regexp-opt during compliation.
|
|
|
|
(eval-and-compile
|
|
(defun ssh-config-ssh-config-keywords-path ()
|
|
"Find the path to 'ssh-config-keywords.txt'.
|
|
It should be next to 'ssh-config-mode.el'.
|
|
When testing add '.' to load-path so you find the local copy."
|
|
(let ((path (locate-library "ssh-config-keywords.txt" nil)))
|
|
;;(message "ssh-config-keywords.txt is %s" path)
|
|
path)))
|
|
|
|
(eval-and-compile
|
|
(defun ssh-config-read-keywords (&optional file-path)
|
|
"Read the list of ssh keywords, returning them as a list."
|
|
;; (message "ssh-config-read-keywords")
|
|
(let ((file-path
|
|
(or file-path
|
|
(ssh-config-ssh-config-keywords-path))))
|
|
(with-temp-buffer
|
|
(insert-file-contents file-path)
|
|
(split-string (buffer-string) "\n" t)))))
|
|
|
|
(eval-and-compile
|
|
(defvar ssh-config-keywords
|
|
(eval-when-compile
|
|
(ssh-config-read-keywords)))
|
|
"A list of keywords allowed in a user ssh config file.")
|
|
|
|
(eval-and-compile
|
|
(defvar ssh-config-font-lock-keywords
|
|
(eval-when-compile
|
|
`((
|
|
,(regexp-opt ssh-config-keywords 'words)
|
|
(1 font-lock-keyword-face)
|
|
)))
|
|
"Expressions to hilight in `ssh-config-mode'."))
|
|
;; ssh-config-font-lock-keywords
|
|
|
|
;; Setup
|
|
(defvar ssh-config-mode-load-hook nil
|
|
"*Hook to run when `ssh-config-mode' is loaded.")
|
|
|
|
;;
|
|
(defvar ssh-config-mode-hook nil
|
|
"*Hook to setup `ssh-config-mode'.")
|
|
|
|
(defvar ssh-config-host-regexp "^\\s-*Host\\b"
|
|
"Regexp to match the start of a host entry.")
|
|
|
|
(defvar ssh-config-match-regexp "^\\s-*Match\\b"
|
|
"Regexp to match the start of a match entry.")
|
|
|
|
(defvar ssh-config-hostname-regexp
|
|
"[-_.a-zA-Z0-9]+"
|
|
"Regexp to match one hostname. (rfc1123 2.1).")
|
|
|
|
(defcustom ssh-config-mode-indent 2
|
|
"The width of indentation to use.
|
|
By default it's set to 2 as that is what man page
|
|
ssh_config(5) shows it as."
|
|
:type 'integer
|
|
:group 'ssh-config-mode)
|
|
|
|
(defun ssh-config-host-next ()
|
|
"Skip to the next host entry."
|
|
(interactive "^")
|
|
(search-forward-regexp ssh-config-host-regexp))
|
|
|
|
(defun ssh-config-host-prev ()
|
|
"Skip to the previous host entry."
|
|
(interactive "^")
|
|
(search-backward-regexp ssh-config-host-regexp))
|
|
|
|
(defun ssh-config-in-host-block-p ()
|
|
"Are we inside a Host block?"
|
|
(save-excursion
|
|
(search-backward-regexp ssh-config-host-regexp nil t)))
|
|
|
|
(defun ssh-config-in-match-block-p ()
|
|
"Are we inside a Match block?"
|
|
(save-excursion
|
|
(search-backward-regexp ssh-config-match-regexp nil t)))
|
|
|
|
(defun ssh-config-compute-indent ()
|
|
"Compute the target indent for the current line.
|
|
Comments right above a 'Host' are considered to be about that Host."
|
|
(save-excursion
|
|
(beginning-of-line)
|
|
(cond
|
|
;; Start of file and "Host" and "Match" should be at 0
|
|
((or (looking-at ssh-config-host-regexp)
|
|
(looking-at ssh-config-match-regexp)
|
|
(and (not (ssh-config-in-host-block-p))
|
|
(not (ssh-config-in-match-block-p))))
|
|
0)
|
|
;; Comment line
|
|
((looking-at "\\s-*#")
|
|
;; comments right before a "Host" or "Match" should be at 0
|
|
(while (looking-at "\\s-*#")
|
|
(forward-line))
|
|
(if (or (looking-at ssh-config-host-regexp)
|
|
(looking-at ssh-config-match-regexp))
|
|
0
|
|
ssh-config-mode-indent))
|
|
;; default.
|
|
(t
|
|
ssh-config-mode-indent))))
|
|
|
|
(defun ssh-config-indent-line ()
|
|
"Indent lines in the SSH config file."
|
|
(interactive)
|
|
(let ((target (ssh-config-compute-indent)))
|
|
(save-excursion
|
|
(indent-line-to target))))
|
|
|
|
;;
|
|
(defvar ssh-config-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
;; Ctrl bindings
|
|
(define-key map [C-down] 'ssh-config-host-next)
|
|
(define-key map [C-up] 'ssh-config-host-prev)
|
|
;;
|
|
(define-key map "\C-c}" 'ssh-config-host-next)
|
|
(define-key map "\C-c{" 'ssh-config-host-prev)
|
|
;;
|
|
(define-key map (kbd "TAB") 'indent-for-tab-command)
|
|
map)
|
|
"The local keymap for `ssh-config-mode'.")
|
|
|
|
;;
|
|
(defvar ssh-config-mode-syntax-table nil)
|
|
(unless ssh-config-mode-syntax-table
|
|
(let ((table (make-syntax-table)))
|
|
(modify-syntax-entry ?# "<" table)
|
|
(modify-syntax-entry ?\n ">" table)
|
|
(setq ssh-config-mode-syntax-table table)))
|
|
|
|
(defvar ssh-config-imenu-generic-expression
|
|
`(("Hosts"
|
|
,(concat ssh-config-host-regexp "\\s-+\\(" ssh-config-hostname-regexp "\\)") 1)
|
|
("Matches"
|
|
,(concat ssh-config-match-regexp "\\s-+\\(.*\\)") 1))
|
|
"Value for `imenu-generic-expression' in `ssh-config-mode'.
|
|
Only show the first hostname in the menu.")
|
|
|
|
;;;###autoload
|
|
(define-derived-mode ssh-config-mode
|
|
fundamental-mode
|
|
"ssh-config"
|
|
"Major mode for fontifiying ssh config files.
|
|
|
|
\\{ssh-config-mode-map}"
|
|
(setq
|
|
comment-start "#"
|
|
comment-end "")
|
|
(make-local-variable 'font-lock-defaults)
|
|
(setq
|
|
font-lock-defaults '(ssh-config-font-lock-keywords nil t))
|
|
;;
|
|
(setq-local indent-line-function 'ssh-config-indent-line)
|
|
(setq-local imenu-generic-expression ssh-config-imenu-generic-expression))
|
|
|
|
;;;###autoload
|
|
(progn
|
|
(add-to-list 'auto-mode-alist '("/\\.ssh/config\\'" . ssh-config-mode))
|
|
(add-to-list 'auto-mode-alist '("/sshd?_config\\'" . ssh-config-mode))
|
|
(add-to-list 'auto-mode-alist '("/known_hosts\\'" . ssh-known-hosts-mode))
|
|
(add-to-list 'auto-mode-alist '("/authorized_keys\\'" . ssh-authorized-keys-mode)))
|
|
|
|
;;;;;
|
|
|
|
(defvar ssh-known-hosts-mode-hook nil
|
|
"*Hook to setup `ssh-config-mode'.")
|
|
|
|
(defvar ssh-known-hosts-mode-map
|
|
(let ((map (make-sparse-keymap)))
|
|
;; Ctrl bindings
|
|
map)
|
|
"The local keymap for `ssh-known-hosts-mode'.")
|
|
|
|
(defvar ssh-known-hosts-mode-syntax-table
|
|
(let ((table (make-syntax-table)))
|
|
(modify-syntax-entry ?# "<" table)
|
|
(modify-syntax-entry ?\n ">" table)
|
|
table)
|
|
"Syntax table for `ssh-known-hosts-mode'.
|
|
Just sets the comment syntax.")
|
|
|
|
;; NOTE: font-lock-studio might be of help when making changes.
|
|
(defvar ssh-known-hosts-font-lock-keywords
|
|
;; We want to match lines like the following:
|
|
;; Short list in ./tests/known_hosts_short
|
|
;; Full list in ./tests/known_hosts
|
|
`(
|
|
(,(concat
|
|
"^"
|
|
;; @marker (optional):
|
|
"\\(@[-a-z]+ +\\|\\)"
|
|
|
|
;; hostnames & hashes:
|
|
;; host.example.com,1.1.1.1
|
|
;; |1|hash|hash|
|
|
;; Just checking for chars, not parsing it.
|
|
"\\("
|
|
"[-0-9A-Za-z|=.,:*/+]+"
|
|
"\\)"
|
|
"[ \t]+"
|
|
|
|
;; key type:
|
|
;; ssh-rsa, ecdsa-sha2-nistp384, ...
|
|
"\\(\\(?:ecdsa\\|ssh\\)[-0-9A-Za-z]*\\)"
|
|
"[ \t]+"
|
|
|
|
;; public key:
|
|
;; base64data==
|
|
"\\(AA[0-9A-Za-z/+]+=*\\)"
|
|
)
|
|
(1 font-lock-warning-face)
|
|
(2 font-lock-function-name-face)
|
|
(3 font-lock-keyword-face)
|
|
(4 font-lock-string-face)
|
|
))
|
|
"Expressions to hilight in `ssh-known-hosts-mode'.")
|
|
|
|
;;;###autoload
|
|
(defun ssh-known-hosts-mode ()
|
|
"Major mode for fontifiying ssh known_hosts files.
|
|
\\{ssh-known-hosts-mode}"
|
|
(interactive)
|
|
(kill-all-local-variables)
|
|
(set-syntax-table ssh-known-hosts-mode-syntax-table)
|
|
(setq
|
|
mode-name "ssh-known-hosts"
|
|
major-mode 'ssh-known-hosts-mode
|
|
comment-start "#"
|
|
comment-end "")
|
|
(use-local-map ssh-known-hosts-mode-map)
|
|
;;
|
|
(make-local-variable 'font-lock-defaults)
|
|
(setq font-lock-defaults '(ssh-known-hosts-font-lock-keywords))
|
|
;;
|
|
(run-hooks 'ssh-known-hosts-mode-hook)
|
|
nil)
|
|
|
|
;;;;;
|
|
|
|
;;;###autoload (autoload 'ssh-authorized-keys-mode "ssh-config-mode" nil t)
|
|
(define-generic-mode ssh-authorized-keys-mode
|
|
'(?\#)
|
|
nil
|
|
(eval-when-compile
|
|
(list
|
|
(list
|
|
(concat
|
|
;; ignore options
|
|
;; double quoted string will be fontified by generic mode.
|
|
;; key type
|
|
"\\(\\(?:ecdsa\\|ssh\\)-[^[:space:]]+\\)\\s-+"
|
|
;; base64
|
|
"\\([0-9A-Za-z+/]+=*\\)"
|
|
;; comment in public key
|
|
"\\(?: \\(.*\\)\\)?"
|
|
"$")
|
|
'(1 font-lock-keyword-face)
|
|
'(2 font-lock-string-face)
|
|
'(3 font-lock-comment-face nil t)
|
|
)))
|
|
;; Not define `auto-mode-alist' obey the other mode in this elisp.
|
|
nil
|
|
nil)
|
|
|
|
;; done loading
|
|
(run-hooks 'ssh-config-mode-load-hook)
|
|
(provide 'ssh-config-mode)
|
|
|
|
;;; ssh-config-mode.el ends here
|