scottcs/dot_hammerspoon

Auto-populating cheatsheets

Closed this issue · 1 comments

Do you have any interest in code to auto-populate new cheatsheets from the application menus? I adapted the code below from https://github.com/dharmapoudel/hammerspoon-config. I'm using tables in my cheatsheets since I like the way they look, and since the format is hard-coded into getAllMenuItems you would have to edit the code to change it. I've been trying to come up with a way to make the format configurable, but haven't come up with any ideas I like.

I added the below code to cheatsheets.lua and added a call to

    ufile.append(file, getAllMenuItems(hs.application.frontmostApplication():getMenuItems()))

after the ufile.create() in editCheatSheet(). (if you prefer I can send you a pull request with my changes if you want to include them)

-- Walk application menus to auto-populate new cheatsheet
-- Original code from https://github.com/dharmapoudel/hammerspoon-config

-- Map modifiers to MenuBarItem modifier indicies
local commandEnum = {
        [0] = '',
        [1] = '⇧ ⌘',
        [2] = '⌥ ⌘',
        [3] = '⌥ ⇧ ⌘',
        [4] = '⌃ ⌘',
        [5] = '⇧ ⌃ ⌘',
        [6] = '⌃ ⌥ ⌘',
        [7] = '',
        [8] = '',
        [9] = '',
        [10] = '',
        [11] = '⌥ ⇧',
        [12] = '',
        [13] = '⌃ ⇧',
        [14] = '⌃ ⌥',
    }

local function getAllMenuItems(app)
  local menu = ''
  for pos,val in pairs(app) do
    if(type(val)=='table') then
      -- do not include help menu for now until I find best way to remove menubar items with no shortcuts in them
      if(val['AXRole'] =='AXMenuBarItem' and type(val['AXChildren']) == 'table') and val['AXTitle'] ~='Help' then
    menu = menu..val['AXTitle']..'\n'..string.rep('=',string.len(val['AXTitle']))..'\n\n'
    menu = menu..'|  |  |\n'
    menu = menu..'| ---: | ------------------------------------------------------- |\n'
    menu = menu.. getAllMenuItems(val['AXChildren'][1])
    menu = menu..'\n'
      elseif(val['AXRole'] =='AXMenuItem' and not val['AXChildren']) then
    if( val['AXMenuItemCmdModifiers'] ~='0' and val['AXMenuItemCmdChar'] ~='') then
      menu = menu..'| '..commandEnum[val['AXMenuItemCmdModifiers']]..' '..val['AXMenuItemCmdChar']..' | '..val['AXTitle']..' |\n'
    end 
      elseif(val['AXRole'] =='AXMenuItem' and type(val['AXChildren']) == 'table') then
    menu = menu..getAllMenuItems(val['AXChildren'][1])
      end
    end
  end
  return menu
end

That's an interesting idea, and I'll have to think about it a bit. I wouldn't want to auto-populate cheatsheets that are more specific than at the app level (for instance, cheatsheets based on current open filetype in vim, or current tmux window, or current website in a browser (which is something I want to support eventually... in fact I should open an issue for that)). But for app-level cheatsheets, I like it as a starting point for new files.

I'm not very happy with the way the cheatsheet file names are currently being created, either. So this might work its way into a refactor of that code. Or possibly, a command could be added to the chooser to auto-generate an app-level cheatsheet.

Yeah, I'll have to think about this, but I like it.