Sublime Forum

An implementation of the Emacs Kill-ring

#1

I’m putting together an implementation of emacs-style cut-and-paste in sublime. So far, I’ve written two commands;

Kill Line: deletes everything until EOL, or the EOL itself if already at EOL. Successive calls add text to the kill ring.
Yank: pastes everything in the kill ring’s most recent entry into the current view at the cursor point.
Yank any: shows the quick panel with all the killed clips. Lets you choose one and insert.

This is all going very well, but I have two problems;

  1. I want to map kill line to ctrl+k, but that isolates the ‘go to one selection’ command that’s currently mapped. what’s the name of the command so I can re-map it to something else?
  2. my yank-any command isn’t working; I’m trying view.insert(pos, text) which works for my normal yank, but fails for for my yank-any. I think it’s because the quick panel is visible while the command is executing, so the text is being pasted into the quick panel rather than the underlying view. Is that possible?
0 Likes

#2
  1. ‘singleSelection’

  2. I suspect it’s that the quick panel is only running window commands, and not view ones. I’ll take a look into it, but in the short term, you can write a window command proxy that will forward the command to the active view.

0 Likes

#3

Thanks, Jon.

A first version of the EmacsKillRing package is available from the wiki;

sublimetextwiki.com/pages/EmacsKillRing.html

0 Likes

#4

(EDIT: have hacked a solution, but it is a hack. details at the end)

Hi Jon. The Text command is being executed, but the insert just isn’t happening. Here’s the code for my yank command:

#
# Yank the most recent kill
#
class EmacsYank(sublimeplugin.TextCommand):
 
  def run(self, view, args):
    global killRing
    valueToYank = killRing.peek()
    for s in view.sel():
      print "YANKING '%s' to (%s, %s) in file '%s'" % (valueToYank, s.begin(), s.end(), view.fileName())
      view.erase(s)
      view.insert(s.begin(), valueToYank)
      
    # once we've yanked, we definitely don't want to
    # reuse the old kill buffer
    killRing.LastKillPosition = -1

Now, if I do a direct call to EmacsYank, using a keybinding, I get this;

YANKING '# reuse the old kill buffer' to (4351, 4351) in file 'C:\Users\Steve\AppData\Roaming\Sublime Text\Packages\EmacsKillRing\EmacsKillRing.py'

So the yank is happening with the right text, at the right point in the right file. But when I invoke that via the quickpanel, I get this;

YANKING '# reuse the old kill buffer' to (0, 0) in file 'None'

Which looks to me like it’s running in the wrong view – I suspect it’s the still-visible quickpanel. The quickpanel doesn’t disappear until after the command has finished running. This is more obvious with a long-running command like a compile.

Anyway, to check that I’m invoking it right, I looked at my invoking command. Here that is;

#
# Yank any clip from the kill ring
# 
class EmacsYankChoice(sublimeplugin.TextCommand):
  def run(self, view, args):
    # choose from the yank-buffer using the quick panel
    global killRing
    choices = killRing.choices()
    names = [name for (idx, name) in choices]
    idx = "%s" % idx for (idx, name) in choices]
    print "YANK CHOICE IN " + view.fileName()
    view.window().showQuickPanel("", "emacsYank", idx, names)

Note the lastt two lines; I print the file name for the view, then call the quickpanel for the view’s window. That print statement says

YANK CHOICE IN C:\Users\Steve\AppData\Roaming\Sublime Text\Packages\EmacsKillRing\EmacsKillRing.py

Which again looks fine.

(EDIT: I’ve hacked a solution, which is that just before showing the quick panel, I store the current view into a global variable. When an item is selected, I use the global variable to paste, and not the view parameter of the run method of EmacsYankChoice

0 Likes

#5

Yeah, that works. Cheers,

0 Likes

#6

Steve - you’re right, the filter text entry was being passed in as the view for text commands. This will be fixed in the next beta.

0 Likes

#7

More commands for emacphiles…

The EmacsKillRing Plugin

If you’ve used emacs, you may be used to a text-manipulation system that is very different from windows cut-and-paste. This is the emacs kill ring, and if you are like me, you miss the ability to hit ctrl+k to kill lines, ctrl+y to yank text back, ctrl+space to set a mark, and ctrl+w to cut a region to the kill buffer.

This package is for you; it implements these emacs commands;

* kill-line (ctrl+k)
* yank (ctrl+y)
* set-mark-command (ctrl+space)
* kill-region (ctrl+w)
* kill-ring-save (alt+w)

These are bound in Sublime Text to the same keys used by a default install of emacs.

This is tightly integrated with the windows clipboard; the most-recent cut is copied to the windows clipboard, and yank is really just paste, remapped.

Additionally, there is another command in the package I’ll call yank-any, which lets you yank any item in the kill ring.

These mapping overwrite singleSelection (ctrl+k) and redo (ctrl+y) so I’ve remapped them;

ctrl+shift+k is the new mapping for singleSelection, which was previously mapped to ctrl+k

ctrl+shift+z is the new mapping for redo, which was previously mapped to ctrl+y

0 Likes