Posted Friday, January 28th, 2011 at 12:45 am under python, tech.

py-narrow-to-class

I can never understand when I meet programmers who don’t use emacs. As a programmer, you spend inordinate amounts of time in your editor. You call yourself a programmer. You like to automate things. You get frustrated when you can’t take matters into your own hands. You like hacking on things. Right? And so…….. why wouldn’t you be deeply attracted to an editor that is fully programmable? Sure, (emacs) lisp may not be to everyone’s liking, but being able to program your editor is hugely powerful, especially when the programming language comes with an extremely strong library of tools just for editing text inside the editor.

Jamu Kakar, another emacs fan was just over at my place. He didn’t know about narrowing the buffer – to only show one section of it so that you can edit it to your heart’s content (e.g., global search & replace) and then widen it again when you’re done. We were looking at some Python code and I did a search. The class we were looking at was long, and I didn’t know if my search had finished in code that was still part of the same class. I said to Jamu “Emacs Python mode should have a function that narrows the buffer to the current class”.

After he was gone, I was thinking about that, and realized it would be easy to write. It’s all of 8 lines.

(defun py-narrow-to-class nil
  (interactive)
  (save-excursion
    (py-beginning-of-def-or-class t)
    (let
        ((start (point)))
      (py-end-of-def-or-class t)
      (narrow-to-region (point) start))))
 

Not too shabby, and it took less than 5 minutes to write it. In words: here’s a function called py-narrow-to-class that takes no arguments and that I want to call interactively (via M-x py-narrow-to-class). It’s going to go to the start of the current Python class, set a local variable called start to remember that location, then move to the end of the class, and narrow the buffer. That’s wrapped in a (save-excursion) so that when all that moving around and narrowing is done, the cursor will be in the exact spot it was when I started. If I want, I can now assign this function to a single keystroke when I’m in Python mode.

If you don’t think that’s pretty neat, you’re probably not a programmer. Can you do that in your editor?

  • http://doteight.com Rob O’Dwyer

    good point about programmers who don’t use programmable editors. I think there’s a bit of a gradient there though, since a lot of editors at least have some sort of plugin system. Most of them can’t match the power of vim or emacs though.

    There is something to be said for being unable to completely break your editor though, which I’ve done numerous times to vim :)

  • http://twitter.com/al_maisan Muharem Hrnjadovic

    Hello Terry,

    nice post, Jamu said on a few occasions “I have learned much about emacs
    by pairing with vim users” :-) it works the other way around as well ..
    your post prompted me to think how I would do this in vim.
    The simplest way is to

    1- enable folding
    :set foldmethod=indent
    zM

    2 – open the fold that contains the class of interest
    zA

    3 – do whatever you want to do with the open fold e.g.
    :folddoopen s/range/xrange/g

    See http://vimdoc.sourceforge.net/htmldoc/fold.html for more detail.

  • flow

    well, i do feel a little ambiguous about this one. it is a very specific method for one very specific use case. most of the time, this use case will not match the problem i have at hand: namely, change the stretch of code i’ve been working on and then change names only in that stretch without risking to break other code. changing names in the entire file, class or method doesn’t meet that requirement. i just select what text i intend to refactor and then do replace on the selection — most of the time it will really be a contiguous stretch. much more generic i think.

  • Brandon Craig Rhodes

    Yes, Emacs narrowing is a really great tool! I only began to take advantage of it one or two years ago, when I discovered that I could write quick presentations for our local Python Atlanta group by writing my slides in Emacs as plain text with ^L (form feed) characters between each slide, then turn on Page Mode and have each slide display separately thanks to the magic of narrowing. I bound “PageUp” and “PageDn” to the Page Mode commands (its native bindings are rather awkward for use during a presentation!) and have been giving presentations that way every since.

    http://www.emacswiki.org/emacs/PageMode

  • http://blogs.fluidinfo.com/terry terrycojones

    You’re welcome! That’s one of the fun things – you can use a tool like emacs for so long and still be unaware of some completely fundametal and great functionality. Happened to me with M-/ (I have it bound to hippie-expand). I discovered it one day years ago and now it’s built into my fingers :-) Emacs is like a big strange country, no-one knows all the corners, and hardly anyone even knows the immediate neigborhood. Reminds me of where I live in Barcelona – after 15 years I’m still discovering places that are just a block or two away.

    BTW, I was introduced to org-mode just last month, and am really enjoying it. Check it out!

  • Anonymous

    Very interesting post thank you. I didn’t know about narrowing either after 15 years of emacs use ;-)

  • http://blogs.fluidinfo.com/terry terrycojones

    Hi Irmen. That sounds good, and reminds me of the folding Occam editor I once used (1987?!). BTW, I think specialized vertical tools can always beat non-specialized horizontal ones (e.g., I do IRC using Konversation, which is really nice, rather than in emacs). But emacs is a pretty powerful horizontal tool – which comes with plenty of challenges / shortcomings, in part because although you *can* do anything, if something’s not provided you do still have to do it :-)

    Thanks for commenting!

  • Irmen

    I can alt-click on the folding triangle in Jedit and it narrows the buffer to that folding block. Not just classes.

  • Pingback: Tweets that mention fluidinfo » Blog Archive » py-narrow-to-class -- Topsy.com()