본문으로 건너뛰기

HCL

프레젠테이션이 YAML을 받는 모든 곳에서 HCL2를 쓸 수 있습니다: HCL 프런트 매터, slides.hcl, kind와 데이터 파일, 표현식과 함수.

HCL은 v0.3.0에 추가되었습니다(go-slides/slides#13).

slides는 YAML을 읽는 모든 곳에서 HCL2의 네이티브 문법도 읽습니다. 표현식과 함수를 쓸 수 있기 때문입니다.

위치YAMLHCL
프런트 매터--- … ------hcl … ---
설정slides.yamlslides.hcl, 먼저 찾음
kind 파일--kinds kinds.yaml, kinds: kinds.yaml이름이 *.hcl인 파일
데이터 파일--data data.yaml 또는 .json이름이 *.hcl인 파일

디렉티브 주석(<!-- class: invert -->)은 Marp와 마찬가지로 YAML로 남고, 프레젠테이션 본문은 그대로 Go 템플릿입니다.

HCL로 쓴 프런트 매터

---hcl
theme    = "gaia"
paginate = true
title    = "Quarterly review"
data = {
  company = "ACME"
  quarter = 3
}
header = format("%s — Q%d", data.company, data.quarter)
footer = "${upper(data.company)} · ${page()}/${total()}"
date   = formatdate("D MMMM YYYY", now())

kind "chapter" {
  extends = "section"
  class   = ["lead", "invert"]
}
---

# {{ .title }}
  • 속성은 같은 이름의 YAML 키에 해당합니다. Marp 디렉티브(theme, paginate, header, footer, class, backgroundColor…), 메타데이터 (title, author…), template, delims, kinds(파일 경로), 그리고 객체인 data가 있습니다.
  • kind "<name>" { … } 블록은 로컬 디렉티브와 extends로 kind(슬라이드 유형)를 정의합니다.
  • 값은 YAML이 주는 것과 같은 문자열 형태로 디렉티브에 전달됩니다. true는 "true"가 되고 클래스 목록은 목록이 되므로, 어느 문법으로 설정했든 디렉티브는 똑같이 동작합니다. null은 디렉티브를 설정하지 않은 상태로 둡니다.
  • **data**는 타입을 유지합니다. 템플릿에서 정수는 int, 그 밖의 수는 float64가 되고, 목록과 객체는 목록과 맵으로 남으므로 {{ add .quarter 1 }}이 동작합니다.
  • HCL 값은 최종 값입니다. Go 템플릿이 그 위에서 다시 실행되지 않습니다.

변수

data는 템플릿 데이터입니다. 프런트 매터 자체의 data 위에 slides.hcl의 데이터, --data 파일, --set이 차례로 덮어씁니다. {{ .company }}를 쓸 수 있는 곳이면 어디서나 "${data.company}"를 쓸 수 있습니다.

프런트 매터 속성은 data.*를 참조할 수 있지만 서로를 참조할 수는 없습니다. footer = title은 오류입니다. 스폿 디렉티브(_class…)는 HCL 식별자가 아니므로 주석으로 쓰십시오.

함수

page(), total(){{ page }}, {{ total }}과 같은 페이지 번호와 마지막 페이지 번호. 푸터에 페이지를 매길 수 있습니다
now(), timestamp()현재 시각(RFC 3339, 로컬 시각과 UTC). formatdate로 서식을 지정합니다
env(name)환경 변수. 설정되지 않았으면 ""
file(path)프레젠테이션이나 설정 파일 기준 상대 경로의 UTF-8 텍스트 파일(최대 1 MiB)
숫자abs ceil floor log max min parseint pow signum
문자열chomp format formatlist join lower regex regexall regexreplace replace split strlen strrev substr title trim trimprefix trimspace trimsuffix upper
컬렉션chunklist coalesce coalescelist compact concat contains distinct element flatten keys length lookup merge range reverse slice sort values zipmap
인코딩csvdecode jsondecode jsonencode
날짜formatdate timeadd

처음 네 행을 제외한 나머지는 모두 go-cty의 표준 라이브러리입니다. 어느 함수도 네트워크에 접근하지 않습니다.

slides.hcl

kinds  = "kinds.hcl"          # or a list of files
themes = ["themes/acme.css"]
data   = { company = "ACME" } # or file paths
html   = false
lang   = "en"

kind "quote" {
  extends = "blank"
  footer  = "${data.company}"
}

알 수 없는 속성은 조용히 무시되지 않고 오류가 됩니다. kind 파일에는 kind 블록을 담으며, 그 밖의 속성은 무시되므로 slides.hcl을 kind 파일로도 쓸 수 있습니다. 데이터 파일의 속성은 데이터의 키가 됩니다.

# data.hcl
company = "ACME"
year    = 2026
motto   = trimspace(file("motto.txt"))

오류

오류는 HCL의 진단 메시지이며, 위치는 프레젠테이션 파일 자체를 기준으로 표시됩니다. 프레젠테이션 넷째 줄의 footer = data.compnay는 다음 오류를 냅니다.

deck.md:4:14: Unsupported attribute: This object does not have an attribute named "compnay".

Marp와 slides expand

Marp도 ---hcl을 프런트 매터의 시작으로 읽지만(Marp의 프런트 매터 규칙은 대시 세 개로 시작하는 첫 줄이면 무엇이든 받아들입니다), 이 블록은 YAML 매핑이 아니므로 아무것도 적용하지 않습니다. 따라서 프레젠테이션은 Marp에서도 렌더링되지만 디렉티브는 빠집니다. 이 동작은 Marp Core 자체의 출력과 비교하는 테스트로 고정되어 있습니다.

slides expand는 프런트 매터를 YAML로 다시 쓰므로, 펼친 프레젠테이션은 일반 Marp이며 slides가 원본을 렌더링한 것과 똑같이 렌더링됩니다.

---
theme: "gaia"
paginate: true
title: "Quarterly review"
header: "ACME — Q3"
footer: "ACME · 1/2"
date: "19 October 2026"
---

라이선스

HCL 지원에는 hashicorp/hcl (MPL-2.0, 수정 없이 라이브러리로 사용)과 zclconf/go-cty(MIT)가 링크됩니다.

Created on by tannevaled

Modified on by tannevaled