---
title: "#구조 #괄호 #편집 Structural-Editing #이맥스"
url: "https://notes.junghanacs.com/notes/20221007T062300"
author: "Junghan Kim"
date: "2022-10-07T06:23:00+09:00"
lastmod: "2025-03-28T00:00:00+09:00"
tags: ["bib","editing","emacs","structure"]
description: "paredit, smartparens, puni를 중심으로 이맥스의 구조적 괄호 편집 개념과 선택지를 모아 둔 자료."
---

> [!abstract] 이 노트에 대하여
> 
> paredit, smartparens, puni를 중심으로 구조적 편집이 왜 리스프와 이맥스에서 중요한지 정리한다. 괄호를 단순 문자로 다루지 않고 구조로 다루는 감각과 패키지 선택지가 함께 묶여 있다.

## BIBLIOGRAPHY

- “Amaikinono/Puni.” 2025. <https://github.com/AmaiKinono/puni>.
- “Fuco1/Smartparens.” 2025. <https://github.com/Fuco1/smartparens>.
- karthink. n.d. “A Consistent Structural Editing Interface - Smartparens Paredit Puni Treesit.” Accessed November 15, 2024. <https://karthinks.com/software/a-consistent-structural-editing-interface/?>

## 용어

-   paredit — parenthetical editing in Emacs
-   Structural Editing on Emacs
-   editing parentheses

## 히스토리

-   [2025-02-11 Tue 15:25] 둠이맥스 smartparens 기본 사용
-   [2023-11-23 Thu 10:13] Puni 사용 중

## 관련노트

-   [#이맥스: #구조적편집 #괄호 #개행 #탈출](https://notes.junghanacs.com/notes/20240704T161606)
-   [#편집](https://notes.junghanacs.com/meta/20250211T153136)

## smartparens / mark-sexp — 상위 폼 한 번에 선택

-   커서가 폼 안/근처에 있을 때:
    -   `C-M-u` (`backward-up-list`) → 바깥으로
    -   `C-M-d` (`down-list`) → 폼 안으로
    -   `C-M-SPC` (`mark-sexp`) → sexp 선택(region)
-   원래 기록(퍼블리시 ID 보존용 스텁): [smartparens mark-sexp (통합됨)](https://notes.junghanacs.com/notes/20250320T103618)

## 깃허브

### AmaiKinono/puni

([“Amaikinono/Puni” 2025](https://notes.junghanacs.com/notes/20221007T062300#citeproc_bib_item_1))

-   AmaiKinono
-   Structured editing (soft deletion, expression navigating &amp; manipulating) that supports many major modes out of the box.
-   

### Fuco1/smartparens

([“Fuco1/Smartparens” 2025](https://notes.junghanacs.com/notes/20221007T062300#citeproc_bib_item_2))

-   Goljer, Matus
-   Minor mode for Emacs that deals with parens pairs and tries to be smart about it.

## A Consistent Structural Editing Interface - smartparens paredit puni treesit

([karthink n.d.](https://notes.junghanacs.com/notes/20221007T062300#citeproc_bib_item_3))

-   karthink

## Corgi : Structural editing

[2023-11-23 Thu 10:19] 돌이켜보니 이게 정말 맛집이었네. Spacemacs 와 거의 유사함

-   `>` slurp forward
-   `<` barf forward
-   `SPC x s` splice backward
-   `SPC x t` transpose sexp
-   `L` forward sexp
-   `H` backward sexp

The latter two are "text objects" that can be combined with other vim-style operations

후자의 두 가지는 다른 vim 스타일 작업과 결합할 수 있는 "텍스트 개체"입니다.

-   `yL` copy next sexp (paste with `p`
-   `dL` delete next sexp
-   `cL` "change" sexp (delete and switch to insert mode)
-   

### Vim-style editing

기본 편집은 모달 에디팅이다. 즉 빔 스타일이라는 말이다. 원칙 파트에서 model vs. key-chord 방식의 차이를 말한다. 왜 빔 스타일로 하느냐에 대한 답으로 RSI 통증에 자유롭다라는 말과 빔 스타일이 훨씬 더 강력한 편집 방식임을 말한다. 특히 연속된 키를 조합해서 만들어내는 강력한 편집 기능을 이야기 한다.

예를 들어, 다음과 같다.

-   '3wd' deletes the next 3 words
-   \`2yL\` copy ("yank") the next 2 s-expressions
-   \`c$\` "change" from cursor position to the end of the line, this deletes the relevant section and changes to insert mode
-   \`cs(]\` change surrounding parenthesis to brackets
-   \`di"\` delete inner string, i.e. delete everything inside the surrounding double quotes

### Differences from Vim

Generally we don't override Evil's keybindings, and Evil in turns emulates vim closely. Some differences

일반적으로 우리는 Evil 의 키 바인딩을 무시하지 않으며 Evil 은 차례로 vim 을 밀접하게 에뮬레이트합니다. 몇 가지 차이점

-   `L` and `H` move forward/backward by one s-expression, instead of moving to the beginning/end of the buffer
-   `SPC` and `,` are both used as leader/prefix keys. Press either and wait a bit to see what they can do.

> These override evil-window-bottom / evil-window-top. I don't like that we are redefining built-in default vim bindings, but we do need a single key motion for forward/backward sexp. Note that to make this work we remove these bindings in init.el from evil-motion-state-map
> 
> 이는 이블윈도우-하단/이블윈도우-상단을 재정의합니다. 내장된 기본 vim 바인딩을 재정의하는 것은 마음에 들지 않지만, 앞으로/뒤로 가기에는 단일 키 모션이 필요합니다. 이 작업을 수행하려면 init.el 에서 다음과 같은 바인딩을 evil-motion-state-map 에서 제거합니다

### NOTE Walkthrough of a Clojure session

When working on a Clojure project I will typically start by opening a `.clj`, `.cljs`, or `.edn` file, and "jacking-in" CIDER. I'll either use `SPC j j` if it's a plain Clojure project (just start a Clojure REPL), or `SPC j a` for both CLJ and CLJS (most CLJS projects I still like to have a CLJ REPL around).

Clojure 프로젝트에서 작업할 때 저는 일반적으로 `.clj`, `.cljs` 또는 `.edn` 파일을 열고 CIDER 를 "재킹-인(jacking-in)"하는 것으로 시작합니다. 일반 Clojure 프로젝트(Clojure REPL 시작)인 경우 `SPC j j` 를 사용하거나 CLJ 와 CLJS 모두에 대해 ~SPC j a~(대부분의 CLJS 프로젝트는 여전히 CLJ REPL 을 사용하고 싶습니다)를 사용합니다.

Once that's started you can jump back and forth to the REPL buffer with `, s s`. When you're done you can close a single REPL with `, s q`, or all connected REPLs for this project with `, s Q`.

일단 시작되면 `, s s` 를 사용하여 REPL 버퍼로 앞뒤로 이동할 수 있습니다. 완료되면 `, s q` 로 단일 REPL 을 닫거나 `, s Q` 로 이 프로젝트에 대해 연결된 모든 REPL 을 닫을 수 있습니다.

If you are running your nREPL sever outside of Emacs, then use `, s c` to connect to it.

Emacs 외부에서 nREPL 서버를 실행하는 경우 `, s c` 를 사용하여 연결하십시오.

To evaluate forms I mainly use `, RET` (evaluate outer form), and `, e p` (evaluate the form before the cursor, and pretty print the result to a separate buffer), but there are a slew of "eval" commands available.

양식을 평가하기 위해 주로 `, RET` (외부 양식 평가) 및 `, e p` (커서 전에 양식을 평가하고 결과를 별도의 버퍼에 예쁘게 인쇄)를 사용하지만 "평가" 명령이 많이 있습니다. 사용 가능.

Inside LISP buffers the `L` and `H` text objects come in handy, these jump back and forth across s-expressions, and can be combined with Vim commands, like `dL` (delete sexp) or `3yL` (copy next 3 sexps).

LISP 버퍼 내부에서 `L` 및 `H` 텍스트 객체가 유용하며, 이들은 s-표현식을 앞뒤로 이동하며 ~dL~(sexp 삭제) 또는 ~3yL~(다음 복사)와 같은 Vim 명령과 결합할 수 있습니다. 3 섹스).

`, g g` is a general binding to jump to an identifier's definition, get used to using this **a lot**. This will also help you explore libraries you're using. `, g b` will pop you back to where you came from.

`, g g` 는 식별자의 정의로 점프하는 일반적인 바인딩입니다. 이 **많은** 사용에 익숙해지세요. 또한 사용 중인 라이브러리를 탐색하는 데 도움이 됩니다. `, g b` 는 원래 있던 곳으로 다시 팝업합니다.

## Coding Tips

[2023-10-06 Fri 17:27]

word 를 ( ) 으로 싸는 방법 -- 중요 'SPC k w' evil-lisp-state-wrap 결국 스마트패런 호출 sp-wrap-around C-c ( 바인딩 잘해놓음

'J' evil-join, 'K' document

Evil : z / g / [ / ] 등 확장 맵 Evil-surround

v-expand to select '(abc)' 'SPC r r' lsp-rename is very useful C-j : new-line and indent without electric-indent-mode ( ) 어떻게 지우지? - delete-pair - evil-surround 도 가능하다.

## 요약

-   이맥스는 리스프로 작성되어 있다. 괄호 편집에 옵션이 다양하다.
-   본 장에서는 paraedit 을 담당하는 Smarparens 패키지를 다룬다.
-   그리고 Evil 에서 제공하는 evil-cleverparens, evil-surround, evil-lisp-state, evil-textobj-line 을 소개한다.

## 2022-10-01 How to use emacs form braveclojure

이게 브레이브 책 2 장에 나오는 내용이다. 올드한 내용이고 EVIL 을 다루지 않았지만 참고하자.

### Core editing terminology and keybinding

단순히 이맥스를 텍스트 편집기로 치부하고 넘어가면 후회할 것이다.

#### 포인트

kill-line undo 키 바인딩을 알려준다.

#### 무브먼트

-   키바인딩이 달라서 적지는 않지만 에빌일 아니라 그런지
-   문장 맨 앞으로, 뒤로, 앞 뒤 캐릭터, 앞 뒤 단어,
-   Regex 검색 `C-s` 라고 나온다. 해보니까 I-Search 라고 뜨는데 이게 뭐지?
-   해당 라인으로 이동하기 나온다.
-   에빌을 사용해도 마찬가지로 편집 모드에서 이동하고 싶다. 그래서 키 매핑 사용

#### Selection with Regions

기본 이맥스에서는 텍스트를 선택하지 않는다고 한다. 그 대신 region 을 만든다. 방법은 `C-SPC` 를 눌러서 'mark' 한다. 그 다음에 포인트를 이동하면 해당 영역은 region 이 된다. 아하.

해보자. 테스트를 해보자. 스페이스맥스에서도 된다. 근데 그냥 비주얼 모드로 하는게 더 쉽다.

#### Killing and the Kill Ring

#### Editing and Help

### Using Emacs with Clojure

#### REPL

#### Windows and Frames

#### Useful Keybinding

-   cider-eval-last-expression
-   namespace ...
-   아래 결과 주석으로 나오게 하는거
-   레플 히스토리 등등

#### Paredit

드디어 왔다. 여기 보려고 본거다. 클로져 버퍼를 편집하는데 왼쪽 괄호를 할 때마다 즉시 오른쪽 괄호가 추가되는 것을 봤는가? 이는 paredit-mode 덕분이다. 그러나, 익숙하지 않다면 이러한 도움은 짜증나게 한다. 토글로 끌 수 있다는 이야기. 여기에 대해서 필요한 키 바인딩을 소개하고 있다. =&gt; paredit 랑 지금 내 설정에서 제공하는건 무엇인가? smartparens 이다. strict 하게 하냐 안하냐 정도 설정한다. 아래 참고.

### Practically :: Structural Editing

여기서 cleverparens, smartparens, lisp state 이야기를 한다. paredit 가 어디에 속하는 것인가? 여기에 하나 문서가 있는데 비교하는 글이다.

#### Paredit and Smartparens

[Paredit and smartparens · Fuco1/smartparens Wiki · GitHub](https://github.com/Fuco1/smartparens/wiki/Paredit-and-smartparens)

#### smartparens 실제 해보자.

=&gt; 스마트패런은 스페이스맥스 기본 패키지이며, 모든 언어를 지원한다. 리스프 계열 뿐만 아니라. 예를 들어 HTML 태그 같은 것도 매한가지다. 이는 전통적인 paraedit 패키지의 새로운 구현이라고 보면 된다. ==&gt; 스페이스 맥스는 Lisp Mode 도 포함한다. 정확히 말하자면 Evil lisp-state 이다. 아하. 이 모드에서는 s/S, b/B, d x, r 이들 캐릭터 입력으로 smartparens 이 가능하다. 그러니까 말그대로 괄호 처리하는 모드이다. ==&gt; VIM 스타일도 지원하는데. normal mode 에서 안전하게 structural 편집을 할 수 있다. 마치 lisp mode 처럼 말이다. 이걸 해주는 모드를 evil-cleverparens 패키지에서 담당한다. --&gt; 닷파일에 toggle-evil-safe-lisp... 넣어둔게 있다. 나는 클로저 모드에서만 활성화되게 해놓았다. 예를 들어, normal mode 에서 모르겠다. 잠시만..

#### Evil Cleverparens safe structural editing 부터 해본다.

문서가 이 순서라 이대로 해보련다. 기본으로 켜놔서 해보니까 괄호 따라가면서 괄호 넣어주고 앞뒤로 가고 뭐 그런다. 딱 visual 모드에서 괄호 처리하는 것이다. 즉, 괄호 많은 코드에서 적절하게 찾아다니면서 수정하겠다는 말이다.

#### Smartparens - 여기를 보자.

아 좋은 영상을 보려고 한다. 4clojure 와도 연계가 된다. 딱이다. 영상에 Alternatives: paraedit and parinfer 가 나온다. 지금 문서는 빠진 것을 보니 18 년도랑 지금은 상황이 다른 것 같다. cursive 에서는 선택으로 parinfer 가 있었다. 왜 없나 했더니 지금은 고민할 단계가 아니다. evil cleverparens, smartparens, lisp state 가 다 다른 특징을 가진다.

내가 생각한 것은 스파트패런이 아닌가 싶다. 내가 알고 있던 키워드가 다 여기로 통합된 것이다. 나머지는 새로운 것(?) 몰랐던 것(?) 이다. 궁금한 지점은 실제 개발할 때 (개인 차가 있겠지만) 뭘 쓰는가이다. 한번 지켜보자.

### `evil` packages

22/10/15--05:37 :: 에빌은 따로 페이지를 만들자.

-   <SPAN CLASS="ORG-HASHTAG">#FIXME</SPAN> 45fa2db9-3a43-4222-b412-2198e662d03a][Evil]] 패키지에 대한 정보는 여기에 담겨 있다.

본 문서에서는 클로저 코딩과 관련한 주제만 다룬다. 스페이스맥스의 `spacemacs-evil` 레이어에 정의되어 있는 것 중에 evil-clerverparens, evil-surround, evil-lisp-state, evil-textobj-line 이정도가 해당하겠다.

### 괄호 삭제,입력,편집,선택

## 2022-11-01 Smartparens 관련 글 [Emacs and Pairs](https://ebzzry.com/en/emacs-pairs/)

### `Smartparens` functions

간단 요약은 아래 블로그에 잘 정리되어 있다. 기능을 하나로 그려보려고 하는 것일 뿐. `cybernetic limbs` 를 가지게 된 것과 같다고 하는 말이 아직 와닿지 않지만 배우는데 드는 시간 그 이상의 가치를 지닌다.

아래 블로그는 네이게이션, 메니플레이션 관점에서 핵심 `함수` 사용법을 다룬다. 그리고 저자의 키 바인딩을 매크로 함수로 제공한다.

### Navigation

#### Start/End

-   sp-beginning-of-sexp
-   sp-end-of-sexp

#### Traversing lists

-   sp-down-sexp
-   sp-up-sexp
-   sp-backward-down-sexp
-   sp-backward-up-sexp

#### Block movements

-   sp-forward-sexp
-   sp-backward-sexp

#### Top-level-ish traversal

-   sp-next-sexp
-   sp-previous-sexp

#### Free-form movements

-   sp-backward-symbol
-   sp-forward-symbol

### Manipulation

#### Wrapping

sp-wrap-with-pair
: 여기에 커스텀 함수를 만들어 보여주네?

#### Unwrapping

-   sp-backward-unwrap-sexp
-   sp-unwrap-sexp

#### Slurp and barf

-   sp-forward-slurp-sexp / sp-backward-slurp-sexp
-   sp-forward-barf-sexp / sp-backward-barf-sexp

#### Swapping

-   `sp-transpose-sexp`

#### Killing

-   `sp-kill-sexp`
-   `sp-kill-hybrid-sexp`
-   `sp-backward-kill-sexp`

### Macro `bind-key`

[Emacs and Pairs :: Bind Key](https://ebzzry.com/en/emacs-pairs/#swapping) 여기에 나와있는 키 바인딩을 요약.

```emacs-lisp

  (defmacro def-pairs (pairs)
  "Define functions for pairing. PAIRS is an alist of (NAME . STRING)
conses, where NAME is the function name that will be created and
STRING is a single-character string that marks the opening character.

  (def-pairs ((paren . \"(\")
              (bracket . \"[\"))

defines the functions WRAP-WITH-PAREN and WRAP-WITH-BRACKET,
respectively."
  `(progn
     ,@(loop for (key . val) in pairs
             collect
             `(defun ,(read (concat
                             "wrap-with-"
                             (prin1-to-string key)
                             "s"))
                  (&optional arg)
                (interactive "p")
                (sp-wrap-with-pair ,val)))))

(def-pairs ((paren . "(")
            (bracket . "[")
            (brace . "{")
            (single-quote . "'")
            (double-quote . "\"")
            (back-quote . "`")))

(bind-keys
 :map smartparens-mode-map
 ("C-M-a" . sp-beginning-of-sexp)
 ("C-M-e" . sp-end-of-sexp)

 ("C-<down>" . sp-down-sexp)
 ("C-<up>"   . sp-up-sexp)
 ("M-<down>" . sp-backward-down-sexp)
 ("M-<up>"   . sp-backward-up-sexp)

 ("C-M-f" . sp-forward-sexp)
 ("C-M-b" . sp-backward-sexp)

 ("C-M-n" . sp-next-sexp)
 ("C-M-p" . sp-previous-sexp)

 ("C-S-f" . sp-forward-symbol)
 ("C-S-b" . sp-backward-symbol)

 ("C-<right>" . sp-forward-slurp-sexp)
 ("M-<right>" . sp-forward-barf-sexp)
 ("C-<left>"  . sp-backward-slurp-sexp)
 ("M-<left>"  . sp-backward-barf-sexp)

 ("C-M-t" . sp-transpose-sexp)
 ("C-M-k" . sp-kill-sexp)
 ("C-k"   . sp-kill-hybrid-sexp)
 ("M-k"   . sp-backward-kill-sexp)
 ("C-M-w" . sp-copy-sexp)
 ("C-M-d" . delete-sexp)

 ("M-<backspace>" . backward-kill-word)
 ("C-<backspace>" . sp-backward-kill-word)
 ([remap sp-backward-kill-word] . backward-kill-word)

 ("M-[" . sp-backward-unwrap-sexp)
 ("M-]" . sp-unwrap-sexp)

 ("C-x C-t" . sp-transpose-hybrid-sexp)

 ("C-c ("  . wrap-with-parens)
 ("C-c ["  . wrap-with-brackets)
 ("C-c {"  . wrap-with-braces)
 ("C-c '"  . wrap-with-single-quotes)
 ("C-c \"" . wrap-with-double-quotes)
 ("C-c _"  . wrap-with-underscores)
 ("C-c `"  . wrap-with-back-quotes))
```

### Cheatsheet

아래 사이트에 요약을 가져 왔다. 이게 원 저자의 키 바인닝이다 [A Cheatsheet for Emacs Smarparens example configuration · GitHub](https://gist.github.com/pvik/8eb5755cc34da0226e3fc23a320a3c95#file-smartparens-cheatsheet-md) ![](https://notes.junghanacs.com/images/2022-10-13_06-36-smartparens-cheat.png)

## Reference

[Emacs and Pairs](https://ebzzry.com/en/emacs-pairs/#swapping)
: Smartparens 를 소개하는 블로그 글

[Enhance Clojure experience · Clojure development with Spacemacs &amp; Cider](https://practical.li/spacemacs/install-spacemacs/enhance-clojure-experience.html)
: 교본

[Structural editing in vanilla Emacs](https://dawranliou.com/blog/structural-editing-in-vanilla-emacs/)
: 고찰을 담은 글

[[<https://www.braveclojure.com/basic-emacs/>][How to Use Emacs, an Excellent Clojure Editor
: Clojure for the Brave and True]] :: 이맥스 편집기 소개 글

## 노트

### deps vs rein

편집 익히는데 영향을 주는 요소가 아니다. 편한거 써도 된다. 배포 프로덕션 하는데 영향을 줄 요소일 뿐. 그러니 신경도 쓰지마라. 지금 하는거에 하나도 문제 안된다. 나중에 바꿀 수도 있다. 아예 눈을 닫아라. 사이더에서 자바 코드 점프하는거. 그건 확인해봐라. 기계인간님 블로그에서 디버깅하는거 있지? 그거 해보고 싶다.

### - <SPAN CLASS="ORG-HASHTAG">#FIXME</SPAN> 5e7bb2b6-3a5a-49d1-8783-aeaffd55faec][기계인간님]] 님 블로그를 보니

#### 클로저 코딩 :: VIM 문서 해당 파트

-   괄호 삭제,입력,편집,선택 자동화해준다는 부분 인줄 알았는데, vim-surround 이야기를 한다. 서라운드는 `텍스트 오브젝트` 다루는 플러그인. 에빌-서라운드가 해주는게 이거겠네.
    
    &gt;&gt; 그렇다면, 서라운드, 섹스피 각각이 이맥스와 기능이 연결된다. 이멕스에 에빌클레버랑 리스프스테이트가 더 있는것 같네.
-   커서 점프 sexp 에서 다양하게 제공한다. vim 스럽지 않게 메타 키 조합 이야기 를 하는 것을 보니 `메타 키` 없이 편집하는게 vim 키 바인딩의 정신이라고 해야하나. 아마 키바인딩 차원에서는 따라가기가 어렵겠다. &gt;&gt; 우리는 키 바인딩 너드가 아니다. 쉽고 좋고 확장 가능한 텍스트 편집 개발 환경이 가지고 싶을 뿐이다.
-   커서 점프 (삽입 모드에서) 삽입 모드에서 편집 중에 괄호 밖으로 점프하는 방법
-   slurp, barf, swap `vim-sexp-mappings-for-regular-people` 설정이 상당히 직관적이다. sexp insert/swap/emit/capture 이런 명령들이네. 이맥스의 어떤 것과 대응되는가?
-   텍스트 오브젝트, 인덴팅, 파일 포메팅, 주석 등이 이후에 쭉 나온다. 이 부분은 본 문서의 토픽이 아니니까 스킵.

#### 생각해 볼 것들...

-   vim-sexp 는 paraedit 를 대신한다고 씌여 있다. (s-expression) 편집을 위한 플러그인. vim-surround 와 병행 사용 ==&gt; 괄호 처리 뭐가 뭐다.
-   파일 구조는 'tagbar'를 사용한다. ctags 와 연동. ==&gt; ibuffer 로 커버되니?
-   `백그라운드 tags 갱신` vim-gutentags 사용. git status 참고해 태그 갱신 ==&gt; 이맥스에 이런게 있나? 있을텐데. 스페이스맥스에 추천 패키지 찾아보라.
