#!/usr/bin/env ruby

# Generate a reference sheet for Kakoune's normal mode
# Use: ./kakmap.rb ../src/normal.cc

require 'markaby'

# Relies on the keymap HashMap assignment ending with };
raw = ARGF.read.split( /const\s+HashMap<Key,\s*NormalCmd>\s+keymap\s*{/ ).last.split( /^};$/ ).first

commands = {}

raw.split( /\n+/ ).each{ |line|
  # skip empty or comment line
  line = line.strip
  if line.empty? or /^\/\// =~ line
    next
  end

  # match key mapping line
  /^\{\s*\{(?<mdky>[^}]+)\}\s*,\s*\{\s*"(?<dsc>[^"]+)"/.match(line) do |m|
    modAndKey = m['mdky']
    des = m['dsc']

    modAndKey.gsub!(/\s*\/\*[^*]+\*\/\s*/, '') # remove comment in key definition

    # match key and modifier
    /Key::(?<key>\w+)|(?<mod>alt|ctrl)\('\\?(?<key>.+?)'\)|'\\?(?<key>.+?)'$/.match(modAndKey) do |sm|
      key = sm['key']
      mod = (sm['mod'] || 'none').to_sym

      key = 'Space' if key == ' '
      commands[key] ||= {}
      commands[key][mod] = des
    end
  end
}

# sort, showing single characters first, symbols next and spelled out keys last
commands = commands.sort_by{ |key, _|
  case key
  when /^\w$/
    key.upcase + key.swapcase
  when /^\W$/
    '_' + key
  else
    '~~' + key
  end
}

puts Markaby::Builder.new {
  html do
    head do
      title "Kakoune default keymap"
    end
    body do
      table :style => "border-collapse: collapse" do
        thead do
          tr do
            th "Key"
            th "Description"
            th "ALT + key"
            th "CTRL + key"
          end
        end
        tbody do
          for key, binding in commands
            tr :style => "border-bottom: 1px solid #fbfbfb" do
              th key
              td binding[:none]
              td binding[:alt]
              td binding[:ctrl]
            end
          end
        end
      end
    end
  end
}