Ruby-mode.el again; imenu this time

Hello,

More ruby-mode.el fun today. The following bit of code, when run
though imenu-add-menubar-index, only creates menu entries for the
first class. It appears to be the fact that they’re in the same module
that’s breaking it:

module Foo
class Bar
def meth1
end
end

class Baz
def meth2
end
end
end

Dan

···


/^Dan Debertin$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

Hi,

···

At Mon, 22 Jul 2002 15:36:45 +0900, Dan Debertin wrote:

More ruby-mode.el fun today. The following bit of code, when run
though imenu-add-menubar-index, only creates menu entries for the
first class. It appears to be the fact that they’re in the same module
that’s breaking it:

ruby-imenu-create-index didn’t work for nested classes. I’m
not sure if this works well enough for singletons.

Index: misc/ruby-mode.el

RCS file: /cvs/ruby/src/ruby/misc/ruby-mode.el,v
retrieving revision 1.53
diff -u -2 -p -r1.53 ruby-mode.el
— misc/ruby-mode.el 28 Jun 2002 14:40:54 -0000 1.53
+++ misc/ruby-mode.el 22 Jul 2002 10:39:15 -0000
@@ -131,26 +131,35 @@

(eval-when-compile (require 'cl))
-(defun ruby-imenu-create-index ()

  • (let ((index-alist '())
  • class-name class-begin method-name method-begin decl)
  • (goto-char (point-min))
  • (while (re-search-forward “^\s *\(class\|def\)\s *\([^(\n ]+\)” nil t)
  •  (setq decl (buffer-substring (match-beginning 1) (match-end 1)))
    

+(defun ruby-imenu-create-index (&optional prefix beg end)

  • (let ((index-alist '()) (nest '()) name name-begin name-end pos decl sing)
  • (goto-char (or beg (point-min)))
  • (while (re-search-forward “^\s *\(class\(\s +<<\)?\|module\|def\|alias\)\s *\([^(\n ]+\)” end t)
  •  (setq sing (match-beginning 2))
    
  •  (setq decl (if sing "class" (buffer-substring (match-beginning 1) (match-end 1))))
    
  •  (setq name-begin (match-beginning 3))
    
  •  (setq name-end (match-end 3))
    
  •  (setq name (buffer-substring name-begin name-end))
    
  •  (setq pos (match-beginning 0))
     (cond
    
  •   ((string= "class" decl)
    
  • (setq class-begin (match-beginning 2))
  • (setq class-name (buffer-substring class-begin (match-end 2)))
  • (push (cons class-name (match-beginning 0)) index-alist)
  • (ruby-mark-defun)
  • (save-restriction
  • (narrow-to-region (region-beginning) (region-end))
    
  •     (while (re-search-forward "^\\s *def\\s *\\([^(\n ]+\\)" nil 'move)
    
  •   (setq method-begin (match-beginning 1))
    
  •   (setq method-name (buffer-substring method-begin (match-end 1)))
    
  •   (push (cons (concat class-name "#" method-name) (match-beginning 0)) index-alist))))
    
  •   ((string= "def" decl)
    
  • (setq method-begin (match-beginning 2))
  • (setq method-name (buffer-substring method-begin (match-end 2)))
  • (push (cons method-name (match-beginning 0)) index-alist))))
  •   ((or (string= "def" decl) (string= "alias" decl))
    
  • (if prefix
  •   (setq name
    
  •     (cond
    
  •      ((string-match "^self\." name)
    
  •       (concat (substring prefix 0 -1) (substring name 4)))
    
  •     (t (concat prefix name)))))
    
  • (push (cons name pos) index-alist))
  •   (t
    
  • (if (string= “self” name)
  •   (if prefix (setq name (substring prefix 0 -1)))
    
  • (if prefix (setq name (concat (substring prefix 0 -1) "::" name)))
    
  • (push (cons name pos) index-alist))
    
  • (ruby-end-of-defun)
  • (setq beg (point))
  • (setq index-alist
  •     (nconc index-alist
    
  •        (ruby-imenu-create-index (concat name (if sing "." "#"))
    
  •   			      name-end beg)))
    
  • (goto-char beg))))
    index-alist))


Nobu Nakada

This is better, but still doesn’t do what I expect. The code fragment
I mentioned:

module Foo
class Bar
def meth1
end
end

class Baz
def meth2
end
end
end

is not a case of nested classes, but of multiple classes within the
same module. The menu, however, comes out nested:

Rescan
Foo
Foo::Bar
Foo::Bar::Baz
Foo::Bar#meth1
Foo::Bar::Baz#meth2

Baz is not a nested class under Bar … right?

Dan

···


/^Dan Debertin$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

Hi,

···

At Tue, 23 Jul 2002 01:32:40 +0900, Dan Debertin wrote:

is not a case of nested classes, but of multiple classes within the
same module. The menu, however, comes out nested:

Rescan
Foo
Foo::Bar
Foo::Bar::Baz
Foo::Bar#meth1
Foo::Bar::Baz#meth2

Baz is not a nested class under Bar … right?

Exactly. ruby-move-to-block was needed to modify to skip RD
style comments.

Still this patch doesn’t work well at here documents…

Index: ruby-mode.el

RCS file: /cvs/ruby/src/ruby/misc/ruby-mode.el,v
retrieving revision 1.53
diff -u -2 -p -r1.53 ruby-mode.el
— ruby-mode.el 28 Jun 2002 14:40:54 -0000 1.53
+++ ruby-mode.el 23 Jul 2002 05:29:00 -0000
@@ -131,26 +131,36 @@

(eval-when-compile (require 'cl))
-(defun ruby-imenu-create-index ()

  • (let ((index-alist '())
  • class-name class-begin method-name method-begin decl)
  • (goto-char (point-min))
  • (while (re-search-forward “^\s *\(class\|def\)\s *\([^(\n ]+\)” nil t)
  •  (setq decl (buffer-substring (match-beginning 1) (match-end 1)))
    

+(defun ruby-imenu-create-index (&optional prefix beg end)

  • (let ((index-alist '()) (nest '()) (case-fold-search nil)
  • name name-begin name-end pos decl sing)
  • (goto-char (or beg (point-min)))
  • (while (re-search-forward “^\s *\(class\(\s +<<\)?\|module\|def\|alias\)\>\s *\([^(\n ]+\)” end t)
  •  (setq sing (match-beginning 2))
    
  •  (setq decl (if sing "class" (buffer-substring (match-beginning 1) (match-end 1))))
    
  •  (setq name-begin (match-beginning 3))
    
  •  (setq name-end (match-end 3))
    
  •  (setq name (buffer-substring name-begin name-end))
    
  •  (setq pos (match-beginning 0))
     (cond
    
  •   ((string= "class" decl)
    
  • (setq class-begin (match-beginning 2))
  • (setq class-name (buffer-substring class-begin (match-end 2)))
  • (push (cons class-name (match-beginning 0)) index-alist)
  • (ruby-mark-defun)
  • (save-restriction
  • (narrow-to-region (region-beginning) (region-end))
    
  •     (while (re-search-forward "^\\s *def\\s *\\([^(\n ]+\\)" nil 'move)
    
  •   (setq method-begin (match-beginning 1))
    
  •   (setq method-name (buffer-substring method-begin (match-end 1)))
    
  •   (push (cons (concat class-name "#" method-name) (match-beginning 0)) index-alist))))
    
  •   ((string= "def" decl)
    
  • (setq method-begin (match-beginning 2))
  • (setq method-name (buffer-substring method-begin (match-end 2)))
  • (push (cons method-name (match-beginning 0)) index-alist))))
  •   ((or (string= "def" decl) (string= "alias" decl))
    
  • (if prefix
  •   (setq name
    
  •     (cond
    
  •      ((string-match "^self\." name)
    
  •       (concat (substring prefix 0 -1) (substring name 4)))
    
  •     (t (concat prefix name)))))
    
  • (push (cons name pos) index-alist))
  •   (t
    
  • (if (string= “self” name)
  •   (if prefix (setq name (substring prefix 0 -1)))
    
  • (if prefix (setq name (concat (substring prefix 0 -1) "::" name)))
    
  • (push (cons name pos) index-alist))
    
  • (ruby-end-of-block)
  • (setq beg (point))
  • (setq index-alist
  •     (nconc index-alist
    
  •        (ruby-imenu-create-index (concat name (if sing "." "#"))
    
  •   			      name-end beg)))
    
  • (goto-char beg))))
    index-alist))

@@ -332,7 +342,7 @@ The variable ruby-indent-level controls
(ruby-expr-beg 'expr-qstr)
(not (looking-at “%=”))

  •          (looking-at "%[Qqrxw]?\\(.\\)"))
    
  •          (looking-at "%[QqrxWw]?\\(.\\)"))
        (goto-char (match-beginning 1))
    
  •     (setq expand (not (eq (char-before) ?q)))
    
  •     (setq expand (not (memq (char-before) '(?q ?w))))
        (setq w (buffer-substring (match-beginning 1)
      			    (match-end 1)))
    

@@ -342,6 +352,5 @@ The variable ruby-indent-level controls
((string= w “(”) (setq re “)(”))
((string= w “<”) (setq re “><”))

  •      ((or (and expand (string= w "\\"))
    
  •   	(member w '("*" "." "+" "?" "^" "$")))
    
  •      ((and expand (string= w "\\"))
          (setq w (concat "\\" w))))
        (unless (cond (re (ruby-forward-string re indent-point t expand))
    

@@ -627,26 +636,33 @@ An end of a defun is found by moving for
(defun ruby-move-to-block (n)
(let (start pos done down)

  • (setq start (ruby-calculate-indent))
  • (if (eobp)
  • nil
  •  (while (and (not (bobp)) (not (eobp)) (not done))
    
  • (forward-line n)
  • (while (not (setq start (ruby-calculate-indent)))
  •  (setq pos t)
    
  •  (forward-line n))
    
  • (if pos (backward-line n))
  • (back-to-indentation)
  • (setq down (looking-at (if (< n 0) ruby-block-end-re ruby-block-beg-re)))
  • (while (and (not done) (not (if (< n 0) (bobp) (eobp))))
  •  (forward-line n)
    
  •  (cond
    
  •   ((looking-at "^\\s *$"))
    
  •   ((looking-at "^\\s *#"))
    
  •   ((and (> n 0) (looking-at "^=begin\\>"))
    
  • (re-search-forward “^=end\>”))
  •   ((and (< n 0) (looking-at "^=end\\>"))
    
  • (re-search-backward “^=begin\>”))
  •   (t
    
  • (setq pos (current-indentation))
    (cond
  • ((looking-at “^$”))
  • ((looking-at “^\s *#”))
  • (t
  • (setq pos (current-indentation))
    
  • (cond
    
  •  ((< start pos)
    
  •   (setq down t))
    
  •  ((and down (= pos start))
    
  •   (setq done t))
    
  •  ((> start pos)
    
  •   (setq done t)))))
    
  • (if done
  •   (progn
    
  •     (back-to-indentation)
    
  •     (if (looking-at ruby-block-mid-re)
    
  •     (setq done nil)))))))
    
  • ((< start pos)
  • (setq down t))
    
  • ((and down (= pos start))
  • (setq done t))
    
  • ((> start pos)
  • (setq done t)))))
    
  •  (if done
    
  • (progn
    
  •   (back-to-indentation)
    
  •   (if (looking-at ruby-block-mid-re)
    
  •   (setq done nil))))))
    
    (back-to-indentation))


Nobu Nakada

Exactly. ruby-move-to-block was needed to modify to skip RD
style comments.

Works perfectly. Many thanks for your work.

Still this patch doesn’t work well at here documents…

Well, at least for imenu it treated this construction correctly:

class Foo
def initialize
instance_eval <<-EOD
def meth1
end
EOD
end
end

But this causes a spurious def to appear in the index:

class Foo
def initialize
print <<-EOD
def meth1
puts "I’m in a fake method"
end
EOD
end
end

As you can see, indenting also thinks I’m in a def. That sounds like
it would be hard to code around, though.

I’m just happy to have a working Imenu. Thanks again.

Dan

···

At Tue, 23 Jul 2002 15:12:07 +0900, nobu.nokada@softhome.net wrote:

/^Dan Debertin$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

Hi,

ruby-mode.el.diff.gz (2.21 KB)

···

At Wed, 24 Jul 2002 01:12:14 +0900, Dan Debertin wrote:

But this causes a spurious def to appear in the index:

class Foo
def initialize
print <<-EOD
def meth1
puts “I’m in a fake method”
end
EOD
end
end

As you can see, indenting also thinks I’m in a def. That sounds like
it would be hard to code around, though.

I see, hope this works.

Well, it’s close ;). Here’s the indentation output:

class Foo
def initialize
print <<-EOD
def foo
end
EOD
end
end

It’s good to see that no bogus method is added to the imenu now
(though it also isn’t added if you define a method under one of the
various _eval methods, and it debatably should be), but as you can
see, it’s not matching up the end-of-here-document token (EOD) and
going back to normal indentation after it.

Dan

···

At Wed, 24 Jul 2002 05:02:51 +0900, nobu.nokada@softhome.net wrote:

I see, hope this works.


/^Dan Debertin$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

Hi,

···

In message “Re: ruby-mode.el again; imenu this time” on 02/07/24, nobu.nokada@softhome.net nobu.nokada@softhome.net writes:

I see, hope this works.

[2 ruby-mode.el.diff.gz <text/x-diff; US-ASCII (base64)>]

Commit them, please.

						matz.

Hi,

I see, hope this works.

[2 ruby-mode.el.diff.gz <text/x-diff; US-ASCII (base64)>]

Commit them, please.

I found ruby-move-to-block got TOO slow, perhaps because of too
many invocations of ruby-calculate-indent and they caused
backtracks. Once I tried forward scan from the beginning,
however it would get slower in larger files, so abandoned.
After all, reverted ruby-move-to-block almost and modified
ruby-imenu-create-index. Both seem to work reasonalbe now.

  • misc/ruby-mode.el (ruby-delimiter): include here document.

  • misc/ruby-mode.el (ruby-imenu-create-index): fix for nested
    classes.

  • misc/ruby-mode.el (ruby-accurate-end-of-block): added. scan a
    block in the order.

  • misc/ruby-mode.el (ruby-expr-beg): support for here document.

  • misc/ruby-mode.el (ruby-parse-partial): splitted from
    ruby-parse-region.

  • misc/ruby-mode.el (ruby-move-to-block): skips RD style comments.

And do you okay to merge this?

  • misc/ruby-mode.el (ruby-deep-arglist): skips spaces after
    parenthesis when 'space.

ruby-mode.el.diff.gz (3.11 KB)

···

At Wed, 24 Jul 2002 10:26:35 +0900, Yukihiro Matsumoto wrote:

Hi,

Commit them, please.

I found ruby-move-to-block got TOO slow, perhaps because of too
many invocations of ruby-calculate-indent and they caused
backtracks. Once I tried forward scan from the beginning,
however it would get slower in larger files, so abandoned.
After all, reverted ruby-move-to-block almost and modified
ruby-imenu-create-index. Both seem to work reasonalbe now.

Hmm, then go ahead.

And do you okay to merge this?

  • misc/ruby-mode.el (ruby-deep-arglist): skips spaces after
    parenthesis when 'space.

Accepted.

						matz.
···

In message “Re: ruby-mode.el again; imenu this time” on 02/07/25, nobu.nokada@softhome.net nobu.nokada@softhome.net writes: