From 6e2a6d1388e25333d1509ae44046b495ed77ed47 Mon Sep 17 00:00:00 2001 From: Maxwell Taylor Date: Tue, 12 Jun 2018 15:01:00 -0400 Subject: [PATCH] feat: add command to open web documentation for resource under point --- terraform-mode.el | 48 ++++++++++++++++++++++++++++++++++++++++++++ test/test-command.el | 31 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/terraform-mode.el b/terraform-mode.el index 15876f0..a5b0cff 100644 --- a/terraform-mode.el +++ b/terraform-mode.el @@ -35,6 +35,7 @@ (require 'rx) (require 'hcl-mode) (require 'dash) +(require 'thingatpt) (defgroup terraform nil "Major mode of Terraform configuration file." @@ -231,6 +232,53 @@ (maphash (lambda (k v) (push `(,k ,@v) menu-list)) search-results) menu-list))) +(defun terraform--extract-provider (resource-name) + "Return the provider associated with a RESOURCE-NAME." + (car (split-string resource-name "_"))) + +(defun terraform--extract-resource (resource-name) + "Return the resource associated with a RESOURCE-NAME." + (mapconcat #'identity (cdr (split-string resource-name "_")) "_")) + +(defun terraform--get-resource-provider-namespace (provider) + "Return provider namespace for PROVIDER." + (let ((provider-info (shell-command-to-string "terraform providers"))) + (with-temp-buffer + (insert provider-info) + (goto-char (point-min)) + (when (re-search-forward (concat "/\\(.*?\\)/" provider "\\]") nil t) + (match-string 1))))) + +(defun terraform--resource-url (resource) + "Return the url containing the documentation for RESOURCE." + (let* ((provider (terraform--extract-provider resource)) + (provider-ns (terraform--get-resource-provider-namespace provider)) + (resource-name (terraform--extract-resource resource))) + (if provider-ns + (format "https://registry.terraform.io/providers/%s/%s/latest/docs/resources/%s" + provider-ns + provider + resource-name) + (user-error "Can not determine the provider namespace for %s" provider)))) + +(defun terraform--resource-url-at-point () + (save-excursion + (goto-char (line-beginning-position)) + (unless (looking-at-p "^resource") + (re-search-backward "^resource" nil t)) + (forward-symbol 2) + (terraform--resource-url (thing-at-point 'symbol)))) + +(defun terraform-open-doc () + "Open a browser at the URL documenting the resource at point." + (interactive) + (browse-url (terraform--resource-url-at-point))) + +(defvar terraform-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-h") #'terraform-open-doc) + map)) + ;;;###autoload (define-derived-mode terraform-mode hcl-mode "Terraform" "Major mode for editing terraform configuration file" diff --git a/test/test-command.el b/test/test-command.el index d6c8de6..6f23e93 100644 --- a/test/test-command.el +++ b/test/test-command.el @@ -22,6 +22,7 @@ ;;; Code: (require 'ert) +(require 'cl-lib) (require 'terraform-mode) (ert-deftest command--beginning-of-defun--from-within-block () @@ -96,4 +97,34 @@ resource \"aws_instance\" \"web\"{ (call-interactively 'hcl-end-of-defun) (should (eobp)))) +(ert-deftest command--open-doc--at-resource-def-line () + (with-terraform-temp-buffer + " +resource \"elasticstack_elasticsearch_security_user\" \"filebeat_writer\" { + username = \"filebeat_writer\" + password = random_password.filebeat_writer.result + roles = [\"filebeat_writer\"] + depends_on = [elasticstack_elasticsearch_security_role.filebeat_writer] +} +" + + (forward-cursor-on "security_user") + (cl-letf (((symbol-function 'terraform--get-resource-provider-namespace) (lambda (prov) "elastic"))) + (should (equal (terraform--resource-url-at-point) "https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/elasticsearch_security_user"))))) + +(ert-deftest command--open-doc--in-body () + (with-terraform-temp-buffer + " +resource \"elasticstack_elasticsearch_security_user\" \"filebeat_writer\" { + username = \"filebeat_writer\" + password = random_password.filebeat_writer.result + roles = [\"filebeat_writer\"] + depends_on = [elasticstack_elasticsearch_security_role.filebeat_writer] +} +" + + (forward-cursor-on "random_password") + (cl-letf (((symbol-function 'terraform--get-resource-provider-namespace) (lambda (prov) "elastic"))) + (should (equal (terraform--resource-url-at-point) "https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/elasticsearch_security_user"))))) + ;;; test-command.el ends here