들여 쓰기 들여 쓰기 계산 소개
더 나은 해결책은 함수를 재정의하는 것 calculate-lisp-indent
입니다. 간단히 말해서, calculate-lisp-indent
한 줄을 들여 쓸 열을 반환하는 함수입니다. 이 함수는 lisp-indent-function
각 줄을 얼마나 들여 쓰기해야 하는지를 알려 줍니다. ( 자세한 내용 은 reddit에 대한 내 게시물 을 참조하십시오).
다른 답변과 비교
이 답변이 Fuco1의 수정 된 기능을 사용하는 것보다 이점은 (1) (2)에 calculate-lisp-indent
의해 반환 된 잘못된 들여 쓰기 후에 정리하는 대신 문제의 근본을 수정한다는 calculate-lisp-indent
것입니다. 그것들이 명시 적으로 인용되거나 역 인용되거나 또는 '
`) 와 함께 인용되는지 여부에 관계없이 작동합니다 . 또한 임의로 중첩 된 따옴표 및 백 따옴표와 함께 작동합니다.
이 답변이 기능으로 대체 lisp-indent-function
하는 common-lisp-indent-function
것의 장점 은 다른 생략 들여 쓰기를 엉망으로 만드는 부작용이 없다는 것입니다. Elisp와 common-lisp는 다르게 들여 쓰기됩니다.
작동 원리
이 조건부 (in calculate-lisp-indent
)는 sexp가 함수처럼 들여 쓰기되는지 여부를 결정하는 것입니다. else 절에 들어가는 것은 함수처럼 들여 쓰기됩니다. if 절에 속하는 것은 정상적으로 (현재 요소 아래) 들여 쓰기됩니다. 따옴표로 묶인 목록을 함수가 아닌 데이터로 들여 쓰기하려면 조건부 술어에서 목록이 인용되는 경우에 대해 더 많은 검사를 추가해야합니다.
(if (= (point) calculate-lisp-indent-last-sexp)
;; Containing sexp has nothing before this line
;; except the first element. Indent under that element.
nil
;; Skip the first element, find start of second (the first
;; argument of the function call) and indent under.
(progn (forward-sexp 1)
(parse-partial-sexp (point)
calculate-lisp-indent-last-sexp
0 t)))
이 코드는 들여 쓰고있는 sexp의 열린 괄호를 확인합니다. 여러 sexp에서 sexp이면 모두 확인합니다. 인용 또는 역 인용 된 sexps를 찾으면 t를 반환합니다.
(let* ((positions (elt state 9))
(last (car (last positions)))
(rest (nreverse (butlast positions)))
(any-quoted-p nil)
(point nil))
(or
(when-let (char last)
(or (char-equal char ?')
(char-equal char ?`)))
(while (and rest (not any-quoted-p))
(setq point (pop rest))
(setq any-quoted-p
(or
(when-let (char point)
(or (char-equal char ?')
(char-equal char ?`)))
(save-excursion
(goto-char (1+ point))
(looking-at-p "\\(?:back\\)?quote[\t\n\f\s]+(")))))))
보너스
인용 부호가없는 경우에도 키워드로 시작하는 목록을 데이터로 들여 쓰려면 조건부 조건부에 다른 검사로 추가하십시오. 이것은 defhydra 와 같이 편의상 plists가 인용되지 않은 매크로에 유용 할 수 있습니다 .
(when-let (char-after (char-after (1+ containing-sexp)))
(char-equal char-after ?:))
예
아래에 게시 한 전체 코드 스 니펫은 언급 한 사례와 더 잘 작동합니다. 사용해보십시오!
;; Your example
`(:token ,token
:token-quality ,quality)
;; Other cool examples
(quote (hi im gosu
the best vayne player))
'(i am the phantom of
the opera)
'((angel of music
hide no longer))
(backquote (past the point
no return
... the final chapter))
`(fee fi fo
fum)
;; should indent it like a function.
(iamafunction arg1
arg2
arg3)
이것이 어떻게 작동하는지에 대한 자세한 설명은 reddit에 대한 게시물을 참조하십시오 .
전체 코드 스 니펫
다음은 전체 코드 스 니펫입니다.
(advice-add #'calculate-lisp-indent :override #'void~calculate-lisp-indent)
(defun void~calculate-lisp-indent (&optional parse-start)
"Add better indentation for quoted and backquoted lists."
;; This line because `calculate-lisp-indent-last-sexp` was defined with `defvar`
;; with it's value ommited, marking it special and only defining it locally. So
;; if you don't have this, you'll get a void variable error.
(defvar calculate-lisp-indent-last-sexp)
(save-excursion
(beginning-of-line)
(let ((indent-point (point))
state
;; setting this to a number inhibits calling hook
(desired-indent nil)
(retry t)
calculate-lisp-indent-last-sexp containing-sexp)
(cond ((or (markerp parse-start) (integerp parse-start))
(goto-char parse-start))
((null parse-start) (beginning-of-defun))
(t (setq state parse-start)))
(unless state
;; Find outermost containing sexp
(while (< (point) indent-point)
(setq state (parse-partial-sexp (point) indent-point 0))))
;; Find innermost containing sexp
(while (and retry
state
(> (elt state 0) 0))
(setq retry nil)
(setq calculate-lisp-indent-last-sexp (elt state 2))
(setq containing-sexp (elt state 1))
;; Position following last unclosed open.
(goto-char (1+ containing-sexp))
;; Is there a complete sexp since then?
(if (and calculate-lisp-indent-last-sexp
(> calculate-lisp-indent-last-sexp (point)))
;; Yes, but is there a containing sexp after that?
(let ((peek (parse-partial-sexp calculate-lisp-indent-last-sexp
indent-point 0)))
(if (setq retry (car (cdr peek))) (setq state peek)))))
(if retry
nil
;; Innermost containing sexp found
(goto-char (1+ containing-sexp))
(if (not calculate-lisp-indent-last-sexp)
;; indent-point immediately follows open paren.
;; Don't call hook.
(setq desired-indent (current-column))
;; Find the start of first element of containing sexp.
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
(cond ((looking-at "\\s(")
;; First element of containing sexp is a list.
;; Indent under that list.
)
((> (save-excursion (forward-line 1) (point))
calculate-lisp-indent-last-sexp)
;; This is the first line to start within the containing sexp.
;; It's almost certainly a function call.
(if (or
;; Containing sexp has nothing before this line
;; except the first element. Indent under that element.
(= (point) calculate-lisp-indent-last-sexp)
;; First sexp after `containing-sexp' is a keyword. This
;; condition is more debatable. It's so that I can have
;; unquoted plists in macros. It assumes that you won't
;; make a function whose name is a keyword.
;; (when-let (char-after (char-after (1+ containing-sexp)))
;; (char-equal char-after ?:))
;; Check for quotes or backquotes around.
(let* ((positions (elt state 9))
(last (car (last positions)))
(rest (reverse (butlast positions)))
(any-quoted-p nil)
(point nil))
(or
(when-let (char (char-before last))
(or (char-equal char ?')
(char-equal char ?`)))
(progn
(while (and rest (not any-quoted-p))
(setq point (pop rest))
(setq any-quoted-p
(or
(when-let (char (char-before point))
(or (char-equal char ?')
(char-equal char ?`)))
(save-excursion
(goto-char (1+ point))
(looking-at-p
"\\(?:back\\)?quote[\t\n\f\s]+(")))))
any-quoted-p))))
;; Containing sexp has nothing before this line
;; except the first element. Indent under that element.
nil
;; Skip the first element, find start of second (the first
;; argument of the function call) and indent under.
(progn (forward-sexp 1)
(parse-partial-sexp (point)
calculate-lisp-indent-last-sexp
0 t)))
(backward-prefix-chars))
(t
;; Indent beneath first sexp on same line as
;; `calculate-lisp-indent-last-sexp'. Again, it's
;; almost certainly a function call.
(goto-char calculate-lisp-indent-last-sexp)
(beginning-of-line)
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp
0 t)
(backward-prefix-chars)))))
;; Point is at the point to indent under unless we are inside a string.
;; Call indentation hook except when overridden by lisp-indent-offset
;; or if the desired indentation has already been computed.
(let ((normal-indent (current-column)))
(cond ((elt state 3)
;; Inside a string, don't change indentation.
nil)
((and (integerp lisp-indent-offset) containing-sexp)
;; Indent by constant offset
(goto-char containing-sexp)
(+ (current-column) lisp-indent-offset))
;; in this case calculate-lisp-indent-last-sexp is not nil
(calculate-lisp-indent-last-sexp
(or
;; try to align the parameters of a known function
(and lisp-indent-function
(not retry)
(funcall lisp-indent-function indent-point state))
;; If the function has no special alignment
;; or it does not apply to this argument,
;; try to align a constant-symbol under the last
;; preceding constant symbol, if there is such one of
;; the last 2 preceding symbols, in the previous
;; uncommented line.
(and (save-excursion
(goto-char indent-point)
(skip-chars-forward " \t")
(looking-at ":"))
;; The last sexp may not be at the indentation
;; where it begins, so find that one, instead.
(save-excursion
(goto-char calculate-lisp-indent-last-sexp)
;; Handle prefix characters and whitespace
;; following an open paren. (Bug#1012)
(backward-prefix-chars)
(while (not (or (looking-back "^[ \t]*\\|([ \t]+"
(line-beginning-position))
(and containing-sexp
(>= (1+ containing-sexp) (point)))))
(forward-sexp -1)
(backward-prefix-chars))
(setq calculate-lisp-indent-last-sexp (point)))
(> calculate-lisp-indent-last-sexp
(save-excursion
(goto-char (1+ containing-sexp))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
(point)))
(let ((parse-sexp-ignore-comments t)
indent)
(goto-char calculate-lisp-indent-last-sexp)
(or (and (looking-at ":")
(setq indent (current-column)))
(and (< (line-beginning-position)
(prog2 (backward-sexp) (point)))
(looking-at ":")
(setq indent (current-column))))
indent))
;; another symbols or constants not preceded by a constant
;; as defined above.
normal-indent))
;; in this case calculate-lisp-indent-last-sexp is nil
(desired-indent)
(t
normal-indent))))))
최종 노트
emacs가 인용 및 인용되지 않은 목록을 함수로 들여 쓰는 것을 막는 방법 으로이 질문을 더 일반화 할 수 있다는 점은 주목할 가치가있다 .