nadvice.el에서 인수 목록을 조작하는 방법은 무엇입니까?


12

에 이어 새로운 자문 시스템에 대한 또 다른 질문에 대한 답변 :

구식에서는 advice.el그렇게 조작되지 않은 멤버에 대한 어떠한 주장도하지 않고 권고 함수의 인수 목록의 개별 멤버를 조작 할 수있었습니다. 예를 들어 다음과 같은 조언이 있습니다.

(defadvice ansi-term (around prompt-for-name last)
  (let ((name (read-from-minibuffer "Tag: ")))
    (and (not (string= name ""))
         (ad-set-arg 1 (concat "Term: " name)))
    ad-do-it))

(선택적) 버퍼 이름 인수를 ansi-term호출에 제공하는 동시에 ansi-term자체 대화식 양식에 따라 프롬프트하여 첫 번째 인수를 얻습니다.

나중에 참조 할 수 있도록 ansi-term의 서명은 (PROGRAM &optional BUFFER-NAME)대화식 양식이며 몇 가지 가능한 기본값으로 PROGRAM을 프롬프트하지만 BUFFER-NAME에 대해서는 아무 것도하지 않습니다.

나는 확실히이 가능 여부 아니에요 nadvice.el. 그렇다면 어떻게 할 수 있는지 잘 모르겠습니다. 조언 된 함수의 인수 목록 을 대체 하는 몇 가지 방법을 찾았습니다 .

예를 들어,에서 * 정보 * (elisp) 조언 콤비 :

`:filter-args'
 Call FUNCTION first and use the result (which should be a list) as
 the new arguments to pass to the old function.  More specifically,
 the composition of the two functions behaves like:
      (lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))

다른 콤비는 유사한 기능을 제공하고, 그들 사이의 공통점은 함수의 인수 목록을 대체 할 수있는 반면, 절단, 연장 등은 목록에서 지정된 위치에 인수를 수정할 수있는 기능에 대한 조언을 명백한 방법이 없다, 그입니다 없이 나머지 부분에 대해서는 아무 것도 주장하지 않습니다 .

논의중인 경우, 어드바이저 작성자가 ansi-term버퍼 이름 만 전달하는 것은 불가능 합니다. 위치 1에는 값이 있지만 nil위치 0에는 없는 값을 갖는 목록을 구성 할 수 없기 때문입니다 . 일반적으로 어드바이저 작성자가 위치 0 이상의 인수를 임의로 수정하는 것은 불가능합니다.

유감스럽게도 비슷한 효과를 내기 위해서는 코드를 복사하여 붙여 넣을 필요가 있습니다. 특히 ansi-term대화 형 양식을 복사 하여 취향에 맞게 확장하거나 ansi-term완전히 복사 하여 마찬가지로 확장 할 수 있습니다 . 두 경우 모두, 이제 init 파일에서 Emacs Lisp 배포판의 일부를 재정의해야하는데, 이는 내구성과 미학 측면에서 바람직하지 않은 것으로 나타났습니다.

내 질문은 다음과 같습니다 : 이런 종류의 인수 목록을 처리 할 수 nadvice.el있습니까? 그렇다면 어떻게?


3
당신은 왜 ansi-term 위에 대화 형 명령을 정의하지 않습니까? 나는 이것이 바람직한 해결책이라고 생각합니다.
lunaryorn

1
물론 그렇게하는 데 방해가되지는 않지만, 10 년 동안의 근육 기억의 더 나은 부분을 대체해야 할 것입니다. 가능하다면 피하고 싶습니다.
Aaron Miller

답변:


5

유감스럽게도 비슷한 효과를 내기 위해서는 코드를 복사하여 붙여 넣어야합니다. [...] ansi-term대화식 양식을 복사 할 수 있습니다.

반대로, 실제로는 그렇게 할 필요는 없지만 대화식 형태의 조언 기능을 복사하여 붙여 넣는 것이 좋습니다.

위에서 아래로 질문을 읽었습니다. 내가 코드 블록에 도착했을 때 나는 짐작 당신의 조언는 것을 아마 버퍼 이름을 변경한다. 그러나 나는하지 않았다 알고 나중에 주석으로 서명을 제공 할 때까지.

논의중인 경우, 어드바이저 작성자가 ansi-term버퍼 이름 만 전달하는 것은 불가능한 것으로 보입니다 . 위치 1에 값이 있지만 nil위치 0에 값이없는 목록을 구성 할 수 없기 때문 입니다.

실제로 아무것도 아무것도 아닙니다. :-) 그러나 그것은 거의 관련이 없습니다.

인용 한 문서에서 볼 수 있듯이, advice에 의해 리턴 된 값은 권고 된 함수에 대한 인수로 사용됩니다. 반환 값은 변경된 인수뿐만 아니라 모든 인수의 목록이어야합니다.

이전 조언에 최대한 가깝게 유지하려면 다음을 사용하십시오 nadvice.

(defun ansi-term--tag-buffer (args)
  ;; As npostavs pointed out we also have to make sure the list is
  ;; two elements long.  Which makes this approach even more undesirable.
  (when (= (length args) 1)
    (setq args (nconc args (list nil))))
  (let ((name (read-from-minibuffer "Tag: ")))
    (and (not (string= name ""))
         (setf (nth 1 args) (concat "Term: " name))))
  args)

(advice-add 'ansi-term :filter-args 'ansi-term--tag-buffer)

그러나 대신 다음과 같이 조언을 정의하는 것이 좋습니다.

(defun ansi-term--tag-buffer (program &optional buffer-name)
  (list program
        (let ((tag (read-from-minibuffer "Tag: ")))
          (if (string= tag "")
              buffer-name
            (concat "Term: " tag)))))

이 변형은 실제로 자명하다.


첫 번째 변형의 args경우와 같은 호출의 경우 목록 을 확장해야합니다 . (ansi-term "foo")그렇지 않으면 (setf (nth 1 args)...오류가 발생합니다.
npostavs

네 말이 맞아. 두 번째 변형을 사용하는 또 다른 이유-첫 번째 변형에는 버그가 있습니다. ;-) 데모 목적으로 buffer-name필수 라고 가정 하겠습니다.
tarsius

"반대로, 나는 조언 된 기능의 대화 형 형식을 복사하여 붙여 넣는 것이 좋은 생각이라고 생각합니다. 왜 그런가요?" 복사 붙여 넣기 코드는 거의 모든 경우에 나쁜 생각입니다. 왜 안돼?
Aaron Miller

사실 저는이 경우 "복사-붙여 넣기"가 올바른 용어라고 생각하지 않습니다. 그러나 여기서이 용어를 사용하는 것이 적절하더라도 "복사-붙여 넣기 안 함"은 절대적인 규칙이 아니라 휴리스틱입니다. 여기에 적용 다른 휴리스틱 은 "변수와 인수에 의미있는 이름을 부여합니다"와 "어떤 것을 복잡하게하거나 상세하게 표시 할 때 자세한 정보를 제공 할 때"입니다.
tarsius

1
음, 실제로, 이것은 여전히 ​​깨졌습니다. :filter-argsadvice는 권고 된 함수에 대한 인수 목록 인 단일 인수를 얻습니다. 따라서 첫 번째 변형은 삭제해야 &rest하며 두 번째 변형은 일종의 파괴 구조를 사용해야 멋진 이름을 얻을 수 있습니다.
npostavs

3

내가하는 방법은 다음과 같습니다.

(defun my-ansi-term-prompt-for-name (orig-fun program
                                     &optional buffer-name &rest args)
  (apply orig-fun program
         (or buffer-name
             (let ((name (read-string "Tag: ")))
               (and (> (length name) 0)
                    (concat "Term: " name))))
         args))
(advice-add 'ansi-term :around #'my-ansi-term-prompt-for-name)

제가 소개 한 사람이었던 동안 :filter-args개인적으로는 거의 편리하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.