hcl-emacs / terraform-mode Goto Github PK
View Code? Open in Web Editor NEWMajor mode of Terraform configuration file
License: GNU General Public License v3.0
Major mode of Terraform configuration file
License: GNU General Public License v3.0
@rnikoopour I've processed all the pull requests and issues not opened by you (which are more of a discussion points anyhow).
I think we can just arbitrarily decide now to tag version 1.0.0 so things like melpa stable pick it up. The package has enough features to be useful so I don't see a reason not to have a "version" release.
WDYT?
Using 0.4. I have a user_data
section in an AWS resource, which uses the here-doc syntax. The shell script contains the character sequence /*
as part of a shell command. This is interpreted as begin multiline quote and break highlighting for the remainder of the file.
It's different, and simpler.
Hi
At leaset those two faces have hardcoded colors.
Can we inherit from font-lock faces instead? It does not play well with so many colorschemes and I do not see the point of not having them just using font-lock type or variable faces?
resource "aws_subnet" "subnet-1" {
vpc_id = aws_vpc.first-vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "prod-subnet"
}
}
/*
resource "aws_subnet" "subnet-1" {
vpc_id = aws_vpc.first-vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "prod-subnet"
}
}
*/
The words hello and world within the comment end up highlighted.
Expected result:
Things within comments are not highlighted, just like shown in the highlighting code above (on Github).
Version:
0.06
Hi,
first of all thanks for this package!
Is there any chance of putting it on NonGNU ELPA as well? If so, may I suggest to get in touch with @phikal to see what needs to be done?
Hello I'd like to be the new maintainer for this project.
What are the steps involved?
Steps to reproduce:
terraform-indent-level
to 4 (default is 2)terraform-format-buffer
on a .tf
fileThe mode indents the buffer at level 2 instead of 4.
This will also fix terraform-format-on-save
.
The syntax highlighting tests go outside the scope of what is actually provided by terraform-mode
.
The test should only cover syntax highlighting directly provided by terraform-mode
$ make
cask exec emacs -Q -batch -L . -l test/test-helper.el \
-l test/test-highlighting.el -l test/test-indentation.el \
-l test/test-command.el \
-f ert-run-tests-batch-and-exit
Running 24 tests (2023-02-17 14:53:07+0100, selector ‘t’)
passed 1/24 array-indentation (0.002235 sec)
passed 2/24 assignment-statement (0.000549 sec)
Test atlas-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-62 (apply fn-60 args-61)) (setq form
(let (form-description-64) (if (unwind-protect (setq value-62 (apply
(let ((value-62 'ert-form-evaluation-aborted-63)) (let (form-descrip
(let* ((fn-60 #'face-at-cursor-p) (args-61 (condition-case err (let
(progn (insert "\natlas {\n name = \"foo\"\n}\n") (goto-char (poi
(unwind-protect (progn (insert "\natlas {\n name = \"foo\"\n}\n")
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name atlas-block :documentation "Syntax hi
ert-run-or-rerun-test(#s(ert--stats :selector t :tests [... ... ...
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test atlas-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 3/24 atlas-block (0.000147 sec)
passed 4/24 beginning-of-defun (0.000358 sec)
passed 5/24 boolean-keywords (0.000487 sec)
passed 6/24 change-indent-size (0.000165 sec)
Test data-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-27 (apply fn-25 args-26)) (setq form
(let (form-description-29) (if (unwind-protect (setq value-27 (apply
(let ((value-27 'ert-form-evaluation-aborted-28)) (let (form-descrip
(let* ((fn-25 #'face-at-cursor-p) (args-26 (condition-case err (let
(progn (insert "\ndata \"template_file\" \"userdata\" {\n source
(unwind-protect (progn (insert "\ndata \"template_file\" \"userdata\
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name data-block :documentation "Syntax hig
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test data-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 7/24 data-block (0.000261 sec)
passed 8/24 end-of-defun (0.000586 sec)
passed 9/24 indentation-into-block (0.000493 sec)
passed 10/24 indentation-into-nested-block (0.000253 sec)
Test inner-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-137 (apply fn-135 args-136)) (setq f
(let (form-description-139) (if (unwind-protect (setq value-137 (app
(let ((value-137 'ert-form-evaluation-aborted-138)) (let (form-descr
(let* ((fn-135 #'face-at-cursor-p) (args-136 (condition-case err (le
(progn (insert "\nprovisioner \"file\" {\n source = \"conf/myapp.
(unwind-protect (progn (insert "\nprovisioner \"file\" {\n source
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name inner-block :documentation "Syntax hi
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test inner-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 11/24 inner-block (0.000486 sec)
passed 12/24 map-indentation (0.000384 sec)
passed 13/24 map-statement (0.000322 sec)
Test module-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-37 (apply fn-35 args-36)) (setq form
(let (form-description-39) (if (unwind-protect (setq value-37 (apply
(let ((value-37 'ert-form-evaluation-aborted-38)) (let (form-descrip
(let* ((fn-35 #'face-at-cursor-p) (args-36 (condition-case err (let
(progn (insert "\nmodule \"consul\" {\n source = \"foo\"\n}\n") (
(unwind-protect (progn (insert "\nmodule \"consul\" {\n source =
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name module-block :documentation "Syntax h
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test module-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 14/24 module-block (0.000254 sec)
passed 15/24 multiple-line-comment (0.000278 sec)
passed 16/24 no-indentation (0.000117 sec)
passed 17/24 no-indentation-into-comment (0.000094 sec)
passed 18/24 no-indentation-with-empty-line (0.000104 sec)
Test output-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-47 (apply fn-45 args-46)) (setq form
(let (form-description-49) (if (unwind-protect (setq value-47 (apply
(let ((value-47 'ert-form-evaluation-aborted-48)) (let (form-descrip
(let* ((fn-45 #'face-at-cursor-p) (args-46 (condition-case err (let
(progn (insert "\noutput \"address\" {\n value = \"foobar\"\n}\n"
(unwind-protect (progn (insert "\noutput \"address\" {\n value =
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name output-block :documentation "Syntax h
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test output-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 19/24 output-block (0.000127 sec)
Test provider-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-7 (apply fn-5 args-6)) (setq form-de
(let (form-description-9) (if (unwind-protect (setq value-7 (apply f
(let ((value-7 'ert-form-evaluation-aborted-8)) (let (form-descripti
(let* ((fn-5 #'face-at-cursor-p) (args-6 (condition-case err (let ((
(progn (insert "\nprovider \"aws\" {\n access_key = \"foo\"\n}\n"
(unwind-protect (progn (insert "\nprovider \"aws\" {\n access_key
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name provider-block :documentation "Syntax
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test provider-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 20/24 provider-block (0.000429 sec)
Test provisioner-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-57 (apply fn-55 args-56)) (setq form
(let (form-description-59) (if (unwind-protect (setq value-57 (apply
(let ((value-57 'ert-form-evaluation-aborted-58)) (let (form-descrip
(let* ((fn-55 #'face-at-cursor-p) (args-56 (condition-case err (let
(progn (insert "\nresource \"aws_instance\" \"web\" {\n provision
(unwind-protect (progn (insert "\nresource \"aws_instance\" \"web\"
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name provisioner-block :documentation "Syn
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test provisioner-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 21/24 provisioner-block (0.000538 sec)
Test resource-block backtrace:
ert-fail(((should (face-at-cursor-p 'font-lock-builtin-face)) :form
(if (unwind-protect (setq value-17 (apply fn-15 args-16)) (setq form
(let (form-description-19) (if (unwind-protect (setq value-17 (apply
(let ((value-17 'ert-form-evaluation-aborted-18)) (let (form-descrip
(let* ((fn-15 #'face-at-cursor-p) (args-16 (condition-case err (let
(progn (insert "\nresource \"aws_security_group\"\"default\" {\n
(unwind-protect (progn (insert "\nresource \"aws_security_group\"\"d
(save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn
(let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current
(let ((lexical-binding nil)) (let ((temp-buffer (generate-new-buffer
(lambda nil (let ((lexical-binding nil)) (let ((temp-buffer (generat
ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
ert-run-test(#s(ert-test :name resource-block :documentation "Syntax
ert-run-or-rerun-test(#s(ert--stats :selector t :tests ... :test-map
ert-run-tests(t #f(compiled-function (event-type &rest event-args) #
ert-run-tests-batch(nil)
ert-run-tests-batch-and-exit()
command-line-1(("-L" "." "-l" "test/test-helper.el" "-l" "test/test-
command-line()
normal-top-level()
Test resource-block condition:
(ert-test-failed
((should
(face-at-cursor-p 'font-lock-builtin-face))
:form
(face-at-cursor-p font-lock-builtin-face)
:value nil))
FAILED 22/24 resource-block (0.000325 sec)
passed 23/24 single-line-comment (0.000301 sec)
passed 24/24 string-interpolation (0.000117 sec)
Ran 24 tests, 16 results as expected, 8 unexpected (2023-02-17 14:53:08+0100, 1.199346 sec)
8 unexpected results:
FAILED atlas-block
FAILED data-block
FAILED inner-block
FAILED module-block
FAILED output-block
FAILED provider-block
FAILED provisioner-block
FAILED resource-block
make: *** [Makefile:18: test] Error 1
Hi All,
I wanted to do a significant refactor on the code base. As I want to implement some new highlighting, I'm struggling to determine where to put it. This code base relies on hcl-mode
and it blurs the lines between what terraform-mode
is responsible for and what hcl-mode
is responsible for.
The refactor would achieve the following:
terraform-mode
hcl-mode
I'd like to gather thoughts from folks watching this library before going down a refactor and submitting a PR.
Cheers
Satements such as
resource "template_file" "ecs_deploy_policy" {
template = "${path.module}/policies/ecs-deploy-policy.json"
}
and more convoluted
resource "aws_iam_role_policy" "ecs_service_role_policy" {
policy = "${file("${path.module}/policies/ecs-service-role-policy.json")}"
}
breaks the syntax highlighting. Both are valid HSL statements. I find the not escaping double quotes in double quotes quite strange, but to my understanding that's how it is intended.
Highlighting is normal when you open a .tf, but any editing that triggers syntax evaluation breaks highlighting from the start of the here document to the end of the file.
I'm using terraform-mode
, which works great, thanks for sharing!
I use projectile-compile-project
to run terraform plan
while coding.
What I'm missing is to know which is my current workspace, which could be displayed in the modeline.
I'm not sure if the feature could possibly belong here or it should be in a separate, optional package. I've also searched for a magit-like terraform interface, which I haven't found and I might be eventually doing. Maybe there would be better. Or maybe it would be also acceptable here.
Also, never done anything with modeline before (novice elisp'er still), but I might take a stab at it if it would be accepted. I guess it should be no big deal.
EDIT: I've started working on a terraform
transient interface package 😄
EDIT 2: I've published the initial version of terraform-cli 🚀
I tried installing terraform-mode-20201110.1915 via package.el and get the following error:
terraform-mode.el:71:1:Error: rx form ‘regexp’ requires args satisfying ‘stringp’
If I (setq terraform-indent-level 4)
, it is not respected, because indent-line-function
is still bound to hcl-indent-line
indent-line-function is a variable defined in ‘indent.el’.
Its value is ‘hcl-indent-line’
Local in buffer example.tf; global value is indent-relative
For now, I'm just setting hcl-indent-level
to the desired value to work around the issue.
It would be great to hide/show blocks of a terraform file with something like folding mode or outline mode. I put together some code to make it work with outline-minor-mode
. Feel free to adapt it, etc.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Allow simple visibility toggling in outline mode with TAB
;;
(defun my-outline-toggle-or-indent (&optional ARG)
(interactive)
(if (outline-on-heading-p)
(outline-toggle-children)
(indent-for-tab-command ARG)
)
)
(define-key outline-minor-mode-map "\C-i" 'my-outline-toggle-or-indent)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; set outline headings for terraform mode
;;
(defun my-terraform-mode-hook ()
(make-local-variable 'outline-regexp)
(setq outline-regexp
(concat
(mapconcat (lambda (item)
(and (car item) (format "\\(%s\\)" (regexp-quote (car item))))
)
imenu-generic-expression
"\\|")
"[[:blank:]].*{[[:blank:]]*$")
)
(setq outline-heading-alist
(mapcar (lambda (item)
(cons (car item) 2)
)
imenu-generic-expression)
)
(outline-minor-mode 1)
)
(add-hook 'terraform-mode-hook 'my-terraform-mode-hook)
Suggest adding "-no-color" to both instances of the terraform fmt
command to show up better in the output buffer.
Hello
When I hit C-c C-h
on the following code:
data "aws_iam_policy" "managed_policies" {
name = "example"
}
a new web page is opened on aws_iam_policy resource page instead of aws_iam_policy data page.
Could you fix terraform-mode so the right URL is opened ?
Thanks for maintaining terraform-mode
All the best
The following is legal Terraform, but is highlighted incorrectly in a buffer and seems to break the auto-reformatter:
terraform {
backend "s3" {
encrypt = true
bucket = "foobar"
key = "dummy.tfstate"
region = "us-east-2"
}
}
Inline functions such as jsonencode
do not have syntax highlighting.
Ideally all functions in Terraform should be highlighted.
Hi
Resource kubernetes_secret
requires a data parameter. This parameter is wrongly detected as a data source.
For instance:
resource "kubernetes_secret" "wildcard-cert" {
data = {
"tls.key" = file(var.wildcard-tls-key-file)
"tls.crt" = file(var.wildcard-tls-crt-file)
}
type = "kubernetes.io/tls"
}
This triggers the creation of =/{
entry in menu Terraform -> data.
C-h
is used throughout emacs to describe all key binding starting with current prefix. terraform-mode
overwrites it in C-c C-h
.
I think it's customary to use C-c C-d
for mode specific documentation.
Syntax highlighting doesn't properly support 0.12.0 syntax
resource foo bar
should have syntax highlighting to identify the reserved words, the resource type, and the resource name
As stated in the issue, it would be nice to have terraform-format-region
.
Travis CI is failing.
Example failure: https://travis-ci.org/github/emacsorphanage/terraform-mode/builds/741800912
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.