Slide 1

Slide 1 text

VIMPRINT A VIM KEYSTROKE PARSER 28th May, 2013 Drew Neil @nelstrom

Slide 2

Slide 2 text

VIMPRINT should... visualize keystrokes in realtime

Slide 3

Slide 3 text

VIMPRINT should... understand all built-in commands

Slide 4

Slide 4 text

VIMPRINT should... be extensible

Slide 5

Slide 5 text

VimSpeak Turns spoken English into keystrokes https://github.com/AshleyF/VimSpeak

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

VimSplain Turns keystrokes into plain English https://github.com/pafcu/Vimsplain

Slide 8

Slide 8 text

Vimulator Turns live keystrokes into plain English https://github.com/thoughtbot/vimulator

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

VimGolf Logs real keystrokes https://github.com/igrigorik/vimgolf

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

vim -w keystrokes are BUFFERED

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Parslet 1st attempt at parsing Vim keystrokes

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

class Vimprint < Parslet::Parser rule(:start) { match('[iIaAoOsS]').as(:switch) } rule(:typing) { match('[^\e]').repeat.as(:typing) } rule(:terminate) { match('\e').as(:escape) } rule(:insertion) { start >> typing >> terminate } root(:insertion) end

Slide 17

Slide 17 text

gv major stumbling block: switch from Normal mode to Visual mode and select the last selected text

Slide 18

Slide 18 text

Ragel 2nd attempt at parsing Vim keystrokes

Slide 19

Slide 19 text

Ragel state machines can not only recognize byte sequences as regular expression machines do, but can also execute code at arbitrary points in the recognition of a regular language.

Slide 20

Slide 20 text

%%{ machine vim_print; action return { fret; } action push_insert_mode { fcall insert_mode; } escape = 27; input = (any - escape); motion = [hjklbwe0]; switch = [iIaAsSoO]; insert_mode := ( input* escape @return ); normal_mode := ( motion | switch @push_insert_mode )*; }%%

Slide 21

Slide 21 text

2 IN 1 insert_mode normal_mode '0', 'b', 'e', 'h', 'j'..'l', 'w' 'A', 'I', 'O', 'S', 'a', 'i', 'o', 's' / push_insert_mode 3 27 / return DEF

Slide 22

Slide 22 text

action H { @head = p } action T { @tail = p } action EmitMotion { @events << {motion: strokes} } action EmitSwitch { @events << {switch: strokes} } action EmitInput { @events << {input: strokes} } action EmitEscape { @events << {escape: ''} } escape = 27 >H@T @EmitEscape; input = (any - escape) >H@T @EmitInput; motion = [hjklbwe0] >H@T @EmitMotion; switch = [iIaAsSoO] >H@T @EmitSwitch;

Slide 23

Slide 23 text

class VimParser attr_accessor :head, :tail, :data def initialize(listener) @events = listener %% write data; end def process(input) @data = input.unpack("c*") eof = @data.length stack = [] %% write init; %% write exec; end def strokes @data[@head..@tail].pack('c*') end end

Slide 24

Slide 24 text

VimParser.new(recorder = []).process("helihello\e") puts recorder {:motion=>"h"} {:motion=>"e"} {:motion=>"l"} {:switch=>"i"} {:input=>"h"} {:input=>"e"} {:input=>"l"} {:input=>"l"} {:input=>"o"} {:escape=>""} https://gist.github.com/nelstrom/5663083

Slide 25

Slide 25 text

FATAL FLAWS with parsing keystrokes

Slide 26

Slide 26 text

FATAL FLAWS no timestamps {...}

Slide 27

Slide 27 text

FATAL FLAWS no document context :s/{pattern}/{string}/c

Slide 28

Slide 28 text

FATAL FLAWS no filetype detection

Slide 29

Slide 29 text

HALP! https://github.com/nelstrom/vimprint Vimprint Realtime Vim keystroke visualizer