joaotavora / yasnippet

A template system for Emacs
http://joaotavora.github.io/yasnippet/
2.81k stars 311 forks source link

yas/trigger-key overriden by ruby-mode #73

Closed joaotavora closed 13 years ago

joaotavora commented 13 years ago

What steps will reproduce the problem?

  1. place the cursor where a yasnippet should expand
  2. press yas/trigger-key

Steps to make yas work, but without ruby-indent-command fallback.

  1. local-unset-key "TAB" on ruby-mode-hook
  2. place the cursor where yasnippet should expand
  3. press yas/trigger-key

What is the expected output? What do you see instead? When I load yas/global-mode or yas/minor-mode properly I expect yas to establish yas/trigger-key with ruby-indent-command as it's fallback. Instead, "C-h k" shows that ruby-indent-command still holds its binding on [TAB].

Likewise, when I do finally get [TAB] expanding, ruby-indent-command yas/expand should still fallback when there is no yasnippet template to render.

What version of the product are you using? On what operating system? I'm using yasnippet trunk r450, Emacs version 23.0.92.1 compiled for NS on my Macbook running Leopard.

Please provide any additional information below. This sounds a lot like Issue 70, for Python. Though I did see the new addition added to the yas/expand function, which was the mentioned patch in that ticket.

I've tried numerous other things with no luck. While I can get around in elisp, I'm still largely a n00b (hopefully not for long).

Google Code Info: Issue #: 71 Author: justi...@gmail.com Created On: 2009-08-06T18:46:52.000Z Closed On: 2009-08-28T12:44:10.000Z

joaotavora commented 13 years ago

I should also mention, I've tried everything in the FAQs / docs (I believe). Including make-variable-buffer-local and setting the yas/fallback-behavior.

Google Code Info: Author: justi...@gmail.com Created On: 2009-08-06T19:18:35.000Z

joaotavora commented 13 years ago

i use following config: (require 'yasnippet) (yas/initialize) (yas/load-directory "~/.emacs.d/vendor/01base/yasnippet/snippets") (setq yas/global-mode t)

and use hippie: (defun crazycode/indent-and-complete () "Indent line and Complete if point is at end of left a leave word." (interactive) (cond ;; hippie-expand ((looking-at "_>") ;; skip message output (flet ((message (format-string &rest args) nil)) (hippie-expand nil)))) ;; always indent line (indent-for-tab-command))

(setq hippie-expand-try-functions-list '( yas/hippie-try-expand try-expand-dabbrev try-expand-dabbrev-visible try-expand-dabbrev-all-buffers try-expand-dabbrev-from-kill try-complete-file-name try-complete-file-name-partially try-complete-lisp-symbol try-complete-lisp-symbol-partially try-expand-line try-expand-line-all-buffers try-expand-list try-expand-list-all-buffers try-expand-whole-kill)) (add-hook 'ruby-mode-hook (lambda() (local-set-key (kbd "TAB") 'crazycode/indent-and- complete))

It worked!

when i use " (local-set-key (kbd "") 'crazycode/indent-and- complete) ", it not work, so i think maybe it is the diffcult of "TAB" and "".

but my yasnippet's condition is not work, as a sample, in my snippet, follow condition:

condition : (rails/model?)

it will not expand, but in yasnippet 0.5.10, it work.

so i changed it as:

condition : (not (rails/model?))

and it worked!

did yasnippet has some issue?

Google Code Info: Author: crazycode@gmail.com Created On: 2009-08-08T00:03:02.000Z

joaotavora commented 13 years ago

In response to the original issue report, cant reproduce this with vanilla Emacs 23.1.50 and trunk 452's yasnippet-bundle.. However, admit I have done some less-than-well-tested changes to the keybinding mechanism.

Please verify with latest svn and also with a vanilla emacs launch (emacs -Q) then loading yasnippet.el (or preferably, for these kinds of tests yasnippet-bundle.el), then loading snippets then testing whatever you wish to test.

Then carefully trace your steps as in the original report.

If it still persists, send me more information about your particular emacs version and your version of ruby-mode. Use M-x find-library RET "ruby-mode" to find your ruby-mode .el file.

Google Code Info: Author: joaotav...@gmail.com Created On: 2009-08-08T23:36:11.000Z

joaotavora commented 13 years ago

I am also having this problem.

Got latest yasnippet from trunk still have the same issue. using "yas/expand" works but "TAB" keybinding does not work. It is taken over by "ruby-mode".

I also have tried everything in the docs and wiki here.

I am using emacs version 22.3.1.

Google Code Info: Author: nightsha...@gmail.com Created On: 2009-08-20T21:19:49.000Z

joaotavora commented 13 years ago

@nightshade: I haven't had the time yet to debug a bit further... Would you mind following joaotavora's recommendation, and start "emacs -Q", then load ruby-mode and yas to see if a vanilla install fixes the issue?

At the very least it should prove that there is a problem between the two, and not some other third party minor-mode. I'm not sure why Yas would not be able to grab the kbd TAB from ruby-mode, unless somehow ruby-mode is able to reset the setting after yas. Which would make no sense (at least to me right now).

Google Code Info: Author: justi...@gmail.com Created On: 2009-08-20T23:16:41.000Z

joaotavora commented 13 years ago

okay narrowed down problem. "emacs -Q" works with ruby-mode then turning on yasnippet. What doesnt work is also enabling ruby-electric. Here is offending piece from .emacs file, any ideas for work arounds to get ruby-electric to play nice with yasnippet?

; adding ruby electric ;; (add-hook 'ruby-mode-hook ;; (lambda() ;; (add-hook 'local-write-file-hooks ;; '(lambda() ;; (save-excursion ;; (untabify (point-min) (point-max)) ;; (delete-trailing-whitespace) ;; ))) ;; (set (make-local-variable 'indent-tabs-mode) 'nil) ;; (set (make-local-variable 'tab-width) 2) ;; (imenu-add-to-menubar "IMENU") ;; (define-key ruby-mode-map "\C-m" 'newline-and-indent) ;; (require 'ruby-electric) ;; (ruby-electric-mode t) ;; ))

Google Code Info: Author: nightsha...@gmail.com Created On: 2009-08-25T01:57:17.000Z

joaotavora commented 13 years ago

even just doing "emacs -Q" then loading ruby-mode then loading yasnippet it works. As soon as I add "ruby- electric-mode" yasnippet loses its TAB binding and cannot get it back

Google Code Info: Author: nightsha...@gmail.com Created On: 2009-08-25T02:09:02.000Z

joaotavora commented 13 years ago

Please post your version of ruby-electric.el here, or link to its URL.

Google Code Info: Author: joaotav...@gmail.com Created On: 2009-08-25T06:53:44.000Z

joaotavora commented 13 years ago

sorry for the delay. thanks again for all the help ;) Here is the ruby-electric.et:

;; --Emacs-Lisp-- ;; ;; ruby-electric.el --- electric editing commands for ruby files ;; ;; Copyright (C) 2005 by Dee Zsombor . ;; Released under same license terms as Ruby. ;; ;; Due credit: this work was inspired by a code snippet posted by ;; Frederick Ros at http://rubygarden.org/ruby?EmacsExtensions. ;; ;; Following improvements where added: ;; ;; - handling of strings of type 'here document' ;; - more keywords, with special handling for 'do' ;; - packaged into a minor mode ;; ;; Usage: ;; ;; 0) copy ruby-electric.el into directory where emacs can find it. ;; ;; 1) modify your startup file (.emacs or whatever) by adding ;; following line: ;; ;; (require 'ruby-electric) ;; ;; note that you need to have font lock enabled beforehand. ;; ;; 2) toggle Ruby Electric Mode on/off with ruby-electric-mode. ;; ;; Changelog: ;; ;; 2005/Jan/14: inserts matching pair delimiters like {, [, (, ', ", ;; ' and | . ;; ;; 2005/Jan/14: added basic Custom support for configuring keywords ;; with electric closing. ;; ;; 2005/Jan/18: more Custom support for configuring characters for ;; which matching expansion should occur. ;; ;; 2005/Jan/18: no longer uses 'looking-back' or regexp character ;; classes like [:space:] since they are not implemented on XEmacs. ;; ;; 2005/Feb/01: explicitly provide default argument of 1 to ;; 'backward-word' as it requires it on Emacs 21.3 ;; ;; 2005/Mar/06: now stored inside ruby CVS; customize pages now have ;; ruby as parent; cosmetic fixes.

(require 'ruby-mode)

(defgroup ruby-electric nil "Minor mode providing electric editing commands for ruby files" :group 'ruby)

(defconst ruby-electric-expandable-do-re "do\s-$")

(defconst ruby-electric-expandable-bar "\s-(do|{)\s-+|")

(defvar ruby-electric-matching-delimeter-alist '((?[ . ?]) (?( . ?)) (?\' . ?\') (?. ?) (?\" . ?\")))

(defcustom ruby-electric-simple-keywords-re (regexp-opt '("def" "if" "class" "module" "unless" "case" "while" "do" "until" "for" "begin") t) "*Regular expresion matching keywords for which closing 'end' is to be inserted." :type 'regexp :group 'ruby-electric)

(defcustom ruby-electric-expand-delimiters-list '(all) "*List of contexts where matching delimiter should be inserted. The word 'all' will do all insertions." :type '(set :extra-offset 8 (const :tag "Everything" all ) (const :tag "Curly brace" ?{ ) (const :tag "Square brace" ?[ ) (const :tag "Round brace" ?( ) (const :tag "Quote" ?\' ) (const :tag "Double quote" ?\" ) (const :tag "Back quote" ?` ) (const :tag "Vertical bar" ?| )) :group 'ruby-electric)

(defcustom ruby-electric-newline-before-closing-bracket nil "*Controls whether a newline should be inserted before the closing bracket or not." :type 'boolean :group 'ruby-electric)

(define-minor-mode ruby-electric-mode "Toggle Ruby Electric minor mode. With no argument, this command toggles the mode. Non-null prefix argument turns on the mode. Null prefix argument turns off the mode.

When Ruby Electric mode is enabled, an indented 'end' is heuristicaly inserted whenever typing a word like 'module', 'class', 'def', 'if', 'unless', 'case', 'until', 'for', 'begin', 'do'. Simple, double and back quotes as well as braces are paired auto-magically. Expansion does not occur inside comments and strings. Note that you must have Font Lock enabled." ;; initial value. nil ;;indicator for the mode line. " REl" ;;keymap ruby-mode-map (ruby-electric-setup-keymap))

(defun ruby-electric-setup-keymap() (define-key ruby-mode-map " " 'ruby-electric-space) (define-key ruby-mode-map "{" 'ruby-electric-curlies) (define-key ruby-mode-map "(" 'ruby-electric-matching-char) (define-key ruby-mode-map "[" 'ruby-electric-matching-char) (define-key ruby-mode-map "\"" 'ruby-electric-matching-char) (define-key ruby-mode-map "\'" 'ruby-electric-matching-char) (define-key ruby-mode-map "|" 'ruby-electric-bar))

(defun ruby-electric-space (arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (if (ruby-electric-space-can-be-expanded-p) (save-excursion (ruby-indent-line t) (newline) (ruby-insert-end))))

(defun ruby-electric-code-at-point-p() (and ruby-electric-mode (let* ((properties (text-properties-at (point)))) (and (null (memq 'font-lock-string-face properties)) (null (memq 'font-lock-comment-face properties))))))

(defun ruby-electric-string-at-point-p() (and ruby-electric-mode (consp (memq 'font-lock-string-face (text-properties-at (point))))))

(defun ruby-electric-is-last-command-char-expandable-punct-p() (or (memq 'all ruby-electric-expand-delimiters-list) (memq last-command-char ruby-electric-expand-delimiters-list)))

(defun ruby-electric-space-can-be-expanded-p() (if (ruby-electric-code-at-point-p) (let* ((ruby-electric-keywords-re (concat ruby-electric-simple-keywords-re "\s-$")) (ruby-electric-single-keyword-in-line-re (concat "\s-*" ruby-electric-keywords-re))) (save-excursion (backward-word 1) (or (looking-at ruby-electric-expandable-do-re) (and (looking-at ruby-electric-keywords-re) (not (string= "do" (match-string 1))) (progn (beginning-of-line) (looking-at ruby-electric-single-keyword-in-line-re))))))))

(defun ruby-electric-curlies(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (if (ruby-electric-is-last-command-char-expandable-punct-p) (cond ((ruby-electric-code-at-point-p) (insert " ") (save-excursion (if ruby-electric-newline-before-closing-bracket (newline)) (insert "}"))) ((ruby-electric-string-at-point-p) (save-excursion (backward-char 1) (when (char-equal ?# (preceding-char)) (forward-char 1) (insert "}")))))))

(defun ruby-electric-matching-char(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (and (ruby-electric-is-last-command-char-expandable-punct-p) (ruby-electric-code-at-point-p) (save-excursion (insert (cdr (assoc last-command-char ruby-electric-matching-delimeter-alist))))))

(defun ruby-electric-bar(arg) (interactive "P") (self-insert-command (prefix-numeric-value arg)) (and (ruby-electric-is-last-command-char-expandable-punct-p) (ruby-electric-code-at-point-p) (and (save-excursion (re-search-backward ruby-electric-expandable-bar nil t)) (= (point) (match-end 0))) ;looking-back is missing on XEmacs (save-excursion (insert "|"))))

(provide 'ruby-electric)

Google Code Info: Author: nightsha...@gmail.com Created On: 2009-08-27T02:55:16.000Z

joaotavora commented 13 years ago

Hi,

I've had a look at this and it appears that "ruby-electric.el" messes up in some points. In particular it binds itself to ruby-mode-map, which makes it, I think, impossible to add any further minor modes that remap keybindings in ruby-mode.

You might consider ditching ruby-electric or contacting the author so he/she can fix it.

Or try this workaround, add this to your .emacs:

(defun yas/advise-indent-function (function-symbol) (eval (defadvice ,function-symbol (around yas/try-expand-first activate) ,(format "Try to expand a snippet before point, then call%s' as usual" function-symbol) (let ((yas/fallback-behavior nil)) (unless (yas/expand) ad-do-it)))))

(yas/advise-indent-function 'ruby-indent-line)

I'll add this to the FAQ.

Google Code Info: Author: joaotav...@gmail.com Created On: 2009-08-28T12:44:10.000Z

joaotavora commented 13 years ago

Hi,

The code snippet previously posted probably had a bug when `ruby-indent-line' is called non-interactively (which includes calls made by the yas indent routines)

Please replace it with this:

(defun yas/advise-indent-function (function-symbol) (eval (defadvice ,function-symbol (around yas/try-expand-first activate) ,(format "Try to expand a snippet before point, then call%s' as usual" function-symbol) (let ((yas/fallback-behavior nil)) (unless (and (interactive-p) (yas/expand)) ad-do-it)))))

(yas/advise-indent-function 'ruby-indent-line)

Google Code Info: Author: joaotav...@gmail.com Created On: 2009-08-28T14:37:16.000Z

joaotavora commented 13 years ago

The workaround doesnt work, sadly. Thanks for all the help. Ruby electric comes with Ruby itself. I guess for now I have to ditch it (this is how I have been working). It would be nice though to get the auto terminating "{", "|", "end" again though if they could play well together.

Google Code Info: Author: nightsha...@gmail.com Created On: 2009-08-29T20:22:12.000Z

joaotavora commented 13 years ago

The following workaround works for me:

(define-key ruby-mode-map (kbd "TAB") nil)

The problem seems to be that ruby-mode defines TAB to call ruby-indent-line', _in_addition_ to setting indent-line-function', and that ruby-electric reloads that keymap behind yasnippet's back. Removing the binding works around that problem, and indentation still works fine as indent-line-function' is still correctly set toruby-indent-line'.

Google Code Info: Author: martin.k...@gmail.com Created On: 2009-08-29T21:29:01.000Z

joaotavora commented 13 years ago

nightshade: can you post the output of "M-x describe-key RET " after you apply the workaround of yas/advise-indent-function? it should say something like

"TAB runs the command ruby-indent-line which is an interactive Lisp function in `ruby-mode.el'. It is bound to TAB. (ruby-indent-line &optional FLAG)

Correct the indentation of the current ruby line.

This function is advised.

Around-advice yas/try-expand-first': Try to expand a snippet before point, then callruby-indent-line' as usual"

Google Code Info: Author: joaotav...@gmail.com Created On: 2009-08-29T22:06:45.000Z

joaotavora commented 13 years ago

to joaotavora: your workaround is excellent! It works for me. Message when TAB key is pressed, is exactly equal to message in your comment14.

my environment : ubuntu 9.10, emacs 23.1.1, ruby-mode 1.0

ps) nightshade != I

Google Code Info: Author: bootm...@gmail.com Created On: 2009-12-13T14:21:28.000Z