-
-
Save tarruda/ea4b9854955451c66f70 to your computer and use it in GitHub Desktop.
# Snake for Neovim! Adapted from https://gist.github.com/sanchitgangwar/2158084 | |
# To install, create a ~/.vim/rplugin/python/snake.py file with this | |
# code, then run `nvim -c 'UpdateRemotePlugins' -c 'q'` from a shell. | |
# | |
# Make sure you have read the internal help explaining how to setup python | |
# host for external plugins(:help nvim-python) | |
# | |
# To start a new game, use the `:SnakeStart` command on an empty buffer(uses 80 | |
# columns and 20 rows) | |
from threading import Thread, Lock | |
from time import sleep | |
from random import randint | |
import neovim | |
class Game(Thread): | |
def __init__(self, vim): | |
super(Game, self).__init__() | |
self.daemon = True | |
self.vim = vim | |
self.buf = vim.current.buffer | |
self.key = 'right' | |
self.prevKey = 'right' | |
self.score = 0 | |
# Initial snake co-ordinates | |
self.snake = [[4,10], [4,9], [4,8]] | |
# First food co-ordinates | |
self.food = [10,20] | |
self.lock = Lock() | |
self.key_subscribe('k', 'up') | |
self.key_subscribe('j', 'down') | |
self.key_subscribe('h', 'left') | |
self.key_subscribe('l', 'right') | |
self.key_subscribe('<esc>', 'esc') | |
self.key_subscribe('<space>', 'space') | |
# Fill the buffer | |
empty = ' ' * 80 | |
self.buf[0] = empty | |
for n in xrange(20): | |
self.buf.append(empty) | |
# Print the food | |
self.addstr(self.food[0], self.food[1], '*') | |
def key_subscribe(self, key, to): | |
cid = self.vim.channel_id | |
self.vim.command( | |
('nnoremap <silent> <buffer> %s ' + | |
':call rpcnotify(%d, "keypress", "%s")<cr>') % | |
(key, cid, to)) | |
def key_unsubscribe(self, key): | |
self.vim.command('unmap <buffer> %s' % key) | |
def run(self): | |
timeout = 0.05 | |
while self.key != 'esc': | |
sleep(timeout) | |
with self.lock: | |
if self.key == 'space': | |
# If SPACE BAR is pressed pause the snake and wait for | |
# another | |
self.key = None | |
while self.key != 'space': | |
sleep(timeout) | |
self.key = self.prevKey | |
continue | |
# Calculates the new coordinates of the head of the snake. | |
# NOTE: len(snake) increases. This is taken care of later at | |
# [1]. | |
self.snake.insert(0, [ | |
self.snake[0][0] + | |
(self.key == 'down' and 1) + | |
(self.key == 'up' and -1), | |
self.snake[0][1] + | |
(self.key == 'left' and -1) + | |
(self.key == 'right' and 1) | |
]) | |
# If snake crosses the boundaries, make it enter from the other | |
# side | |
if self.snake[0][0] == 0: self.snake[0][0] = 18 | |
if self.snake[0][1] == 0: self.snake[0][1] = 58 | |
if self.snake[0][0] == 19: self.snake[0][0] = 1 | |
if self.snake[0][1] == 59: self.snake[0][1] = 1 | |
l = len(self.snake) | |
trail = self.snake[1:] | |
if self.snake[0] in trail: | |
# Snake runs over itself, game over | |
break | |
# Increases the speed of Snake as its length increases | |
timeout = 0.001 * (150 - (l / 5 + l /10) % 120) | |
self.prevKey = self.key # Previous key pressed | |
self.vim.session.threadsafe_call(self.update) | |
self.vim.session.threadsafe_call(self.end) | |
def addstr(self, lnum, cnum, string): | |
line = self.buf[lnum] | |
line = line[0:cnum] + string + line[cnum + len(string):] | |
self.buf[lnum] = line | |
def update(self): | |
with self.lock: | |
if self.snake[0] == self.food: # When snake eats the food | |
self.food = [] | |
self.score += 1 | |
while self.food == []: | |
# Calculating next food's coordinates | |
self.food = [randint(1, 18), randint(1, 58)] | |
if self.food in self.snake: self.food = [] | |
self.addstr(self.food[0], self.food[1], '*') | |
else: | |
# [1] If it does not eat the food, length decreases | |
last = self.snake.pop() | |
self.addstr(last[0], last[1], ' ') | |
self.addstr(self.snake[0][0], self.snake[0][1], '#') | |
# Printing 'Score' and | |
self.addstr(0, 2, 'Score : ' + str(self.score) + ' ') | |
self.addstr(0, 27, ' SNAKE / MOVEMENTs(hjkl) EXIT(esc) PAUSE(space) ') | |
def end(self): | |
with self.lock: | |
self.buf[:] = None | |
self.buf.append("Score - " + str(self.score)) | |
self.buf.append("http://bitemelater.in") | |
self.key_unsubscribe('k') | |
self.key_unsubscribe('j') | |
self.key_unsubscribe('h') | |
self.key_unsubscribe('l') | |
self.key_unsubscribe('<esc>') | |
self.key_unsubscribe('<space>') | |
def keypress(self, k): | |
self.key = k | |
@neovim.plugin | |
class Snake(object): | |
def __init__(self, vim): | |
self.vim = vim | |
self.current_game = None | |
@neovim.rpc_export('keypress') | |
def keypress(self, key): | |
self.current_game.keypress(key) | |
@neovim.command('SnakeStart', sync=True) | |
def snake_start(self): | |
if self.current_game: | |
raise Exception('Snake already running!') | |
self.current_game = Game(self.vim) | |
self.current_game.start() |
@SirVer It now goes into rplugin
instead of external-plugin
, also the command is now UpdateRemotePlugins
instead of UpdateExternalPlugins
and the help is also now :he remote-plugin
I hope that helps.
@SirVer Just updated the gist, also the docs have improved a bit: http://neovim.org/doc/user/remote_plugin.html#remote-plugin
It concerns me little though since all other python plugins seem to work fine
Thats because other python plugins run over the compatibility layer, which is registered manually(doesn't require UpdateRemotePlugins to work)
Can anyone help me running this? I copied the file to .vim/rplugin/python/snake.py
and :UpdateRemotePlugins
seems to run successfully(it's not printing any errors), but :SnakeStart
is failing with Not an editor command: SnakeStart
.
Do we have a verbose mode for :UpdateRemotePlugins
that prints updated/loaded plugins so that I can make sure this plugin is really loaded?
UPDATE: I'm using 2015-01-16 version.
@osa1 It seems registration code is changed....
@osa1 I tested snake.py and it worked.
Seems like this is not working any longer. Running
:UpdateExternalCommands
gives me:It concerns me little though since all other python plugins seem to work fine. Clipboard is not though. Also, the documentation still seems parse/non existant.