yasnippet과 회사를 더 멋지게 만드는 방법?


22

내 emacs "elisp"에서 org-mode에서 lisp 블록을 확장 하기 위해 yasnippet을 사용한다고 가정 해 봅시다 . 그러나 그것을 확장하기 전에 회사가 먼저 시작 "1. elisp1, 2. elisp2"되어 옵션이없는 메뉴를 제공합니다 "elisp". 이제 tabyasnippet을 확장 하는 데 사용 하면 "elisp1"항상 화면에 항상 표시 되는 것이 항상 짜증납니다 . "1"먼저 먼저 삭제 하고 yasnippet 스 니펫을 확장해야합니다.

솔루션으로 항상 왼쪽 화살표 키를 사용하여 회사 완료 메뉴를 먼저 끄지 만 커서는 이제로 이동합니다 "elis|p". 다시 오른쪽 화살표 키를 사용하여 커서를의 끝으로 이동 "elisp|"하고 스 니펫을 확장합니다.

여기 내 질문이 있습니다 : 어떻게 tab키를 바인딩 하여 yasnippet을 트리거 할 수는 있지만 회사가 생명을 구할 수는 없습니까?


1
tabfor companyC-ofor를 사용 하고 있습니다 yasnippet. 당신이 관심이 있다면 더 설명 할 수 있습니다.
abo-abo

@ abo-abo, 답변 감사합니다. 나는 당신이 할 수있는 일을 알고 있지만, 나는 다른 명령에 Co를 묶습니다. 그리고 나는 손 근육을 적응시키기 위해 훈련했습니다 tab. 따라서 바인딩을 변경하고 싶지 않습니다.
Leu_Grady

그래서 내가 물었습니다 :) C-o관심이 없다면 abbrevs와 snippets 및 open line 등을 확장 하는 방법에 대해 서두르지 않아도됩니다.
abo-abo

흥미로운 것 같습니다, 더 자세히 설명해 주시겠습니까? :)
Leu_Grady

답변:


22

이것은 내가 똑같은 문제에 직면하여 나 자신을 위해 만든 것입니다. 회사 모드의 Emacs Wiki 페이지 에서 가져온 것이지만 크게 확장되었습니다.

(defun check-expansion ()
  (save-excursion
    (if (looking-at "\\_>") t
      (backward-char 1)
      (if (looking-at "\\.") t
    (backward-char 1)
    (if (looking-at "->") t nil)))))

(defun do-yas-expand ()
  (let ((yas/fallback-behavior 'return-nil))
    (yas/expand)))

(defun tab-indent-or-complete ()
  (interactive)
  (cond
   ((minibufferp)
    (minibuffer-complete))
   (t
    (indent-for-tab-command)
    (if (or (not yas/minor-mode)
        (null (do-yas-expand)))
    (if (check-expansion)
        (progn
          (company-manual-begin)
          (if (null company-candidates)
          (progn
            (company-abort)
            (indent-for-tab-command)))))))))

(defun tab-complete-or-next-field ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand)))
      (if company-candidates
      (company-complete-selection)
    (if (check-expansion)
      (progn
        (company-manual-begin)
        (if (null company-candidates)
        (progn
          (company-abort)
          (yas-next-field))))
      (yas-next-field)))))

(defun expand-snippet-or-complete-selection ()
  (interactive)
  (if (or (not yas/minor-mode)
      (null (do-yas-expand))
      (company-abort))
      (company-complete-selection)))

(defun abort-company-or-yas ()
  (interactive)
  (if (null company-candidates)
      (yas-abort-snippet)
    (company-abort)))

(global-set-key [tab] 'tab-indent-or-complete)
(global-set-key (kbd "TAB") 'tab-indent-or-complete)
(global-set-key [(control return)] 'company-complete-common)

(define-key company-active-map [tab] 'expand-snippet-or-complete-selection)
(define-key company-active-map (kbd "TAB") 'expand-snippet-or-complete-selection)

(define-key yas-minor-mode-map [tab] nil)
(define-key yas-minor-mode-map (kbd "TAB") nil)

(define-key yas-keymap [tab] 'tab-complete-or-next-field)
(define-key yas-keymap (kbd "TAB") 'tab-complete-or-next-field)
(define-key yas-keymap [(control tab)] 'yas-next-field)
(define-key yas-keymap (kbd "C-g") 'abort-company-or-yas)

기본적으로 이것은 대부분 의 경우 <tab>올바른 일 을합니다. 탭을 누르면

  • 현재 줄을 들여 쓰기
  • 확장 할 야스 니펫이있는 경우 회사 완성을 중단하는 것을 의미하더라도 확장합니다 (약어를 많이 사용하지 않으므로 약어 지원은 아직 없음),
  • 회사 완료가 진행중인 경우 선택한 항목으로 완료하십시오.
  • 그렇지 않으면 회사를 사용하여 자동 완성을 시작해 봅니다.
  • 자동 완성 할 내용이없고 야스 니펫 플레이스 홀더에있는 경우 다음 플레이스 홀더로 건너 뜁니다.

자동 완성 할 기회가 있고 스 니펫 플레이스 홀더에서 현재 편집중인 경우 상황이 모호합니다. 타협으로 C-<tab>다음 자리 표시 자로 바로 건너 뛰었습니다.

적어도 그것을 입력 할 수 있지만 조각의 이름은 회사의 메뉴와의 존재에 나타나지 않는 사실은 ... 탭 키의 동작이 불행하게도, 특히 좋은하지 않습니다 자동 수정을 니펫을 <return>완료를 대신 얻을 대신 스 니펫


이것은 magit을 방해하는 것 같습니다. magit의 탭을 올리도록 Buffer is read-only: #<buffer *magit: ~/.emacs.d/*>합니다. 어떻게 해결할 수 있습니까?
zsquare

@zsquare 나는 확실하게이 문제를 테스트 할 수 있도록 (내가 너트 해요, 알고)하지만 TAB에 대한 magit의 키 맵, 같은 소리 magit를 사용하지 않는 것이에 결합magit-section-toggle , 라인와 충돌 (global-set-key [tab] 'tab-indent-or-complete)위. tab-indent-or-complete위 의 함수의 시작 부분에 예를 들어 전역 변수가 설정되어 있는지 확인하기 위해 위 의 함수 시작 부분에 검사를 추가하는 것이 빠르고 더러운 수정입니다 magit-mode-hook.
dodgethesteamroller

고마워요! :) 작은 스타일 포인트, when거의 if+입니다progn
Matt Briggs

@zsquare magit 모드에서 탭을 지원하려면 tab-indent-or-complete조건에 추가하십시오. ((derived-mode-p 'magit-mode) (magit-section-toggle (magit-current-section)))
Bae

기본 미니 버퍼 완성 대신 ido를 지원하려면 조건을`((minibufferp) (ido-complete))`로 대체하십시오
Bae

10

사용중인 코드는 다음과 같습니다.

(global-set-key "\C-o" 'aya-open-line)

(defun aya-open-line ()
  "Call `open-line', unless there are abbrevs or snippets at point.
In that case expand them.  If there's a snippet expansion in progress,
move to the next field. Call `open-line' if nothing else applies."
  (interactive)
  (cond ((expand-abbrev))

        ((yas--snippets-at-point)
         (yas-next-field-or-maybe-expand))

        ((ignore-errors
           (yas-expand)))

        (t
         (open-line 1))))

aya-open-line에서 자동 yasnippet 일반보다 더 수행합니다 open-line:

  • 그것은 abbrevs를 확장하려고합니다
  • yasnippet의 다음 필드로 이동하려고합니다.
  • yasnippet을 확장하려고합니다.
  • 마지막으로, open-line다른 모든 것이 실패하면 호출

스 니펫 주셔서 감사합니다. 꽤 좋아요 그러나 문제는 여전히 존재합니다. 처음 사용하면 C-o회사 메뉴가 닫히므로 두 번 눌러 야스 핏을 확장해야합니다.
Leu_Grady

나는 그런 문제가 없습니다 : C-o활성 회사의 메뉴는 메뉴를 닫습니다 함께 하고 미리보기를 확장합니다.
abo-abo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.