PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/examples/data/plugins/completion.py

http://github.com/Dieterbe/uzbl
Python | 179 lines | 165 code | 7 blank | 7 comment | 0 complexity | b4fb997cdb3ede1478eb33974ec4b0f0 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
  1. '''Keycmd completion.'''
  2. import re
  3. # Completion level
  4. NONE, ONCE, LIST, COMPLETE = range(4)
  5. # The reverse keyword finding re.
  6. FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall
  7. # Formats
  8. LIST_FORMAT = "<span> %s </span>"
  9. ITEM_FORMAT = "<span @hint_style>%s</span>%s"
  10. def escape(str):
  11. return str.replace("@", "\@")
  12. def get_incomplete_keyword(uzbl):
  13. '''Gets the segment of the keycmd leading up to the cursor position and
  14. uses a regular expression to search backwards finding parially completed
  15. keywords or @variables. Returns a null string if the correct completion
  16. conditions aren't met.'''
  17. keylet = uzbl.keylet
  18. left_segment = keylet.keycmd[:keylet.cursor]
  19. partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip()
  20. if partial.startswith('set '):
  21. return ('@%s' % partial[4:].lstrip(), True)
  22. return (partial, False)
  23. def stop_completion(uzbl, *args):
  24. '''Stop command completion and return the level to NONE.'''
  25. uzbl.completion.level = NONE
  26. del uzbl.config['completion_list']
  27. def complete_completion(uzbl, partial, hint, set_completion=False):
  28. '''Inject the remaining porition of the keyword into the keycmd then stop
  29. the completioning.'''
  30. if set_completion:
  31. remainder = "%s = " % hint[len(partial):]
  32. else:
  33. remainder = "%s " % hint[len(partial):]
  34. uzbl.inject_keycmd(remainder)
  35. stop_completion(uzbl)
  36. def partial_completion(uzbl, partial, hint):
  37. '''Inject a common portion of the hints into the keycmd.'''
  38. remainder = hint[len(partial):]
  39. uzbl.inject_keycmd(remainder)
  40. def update_completion_list(uzbl, *args):
  41. '''Checks if the user still has a partially completed keyword under his
  42. cursor then update the completion hints list.'''
  43. partial = get_incomplete_keyword(uzbl)[0]
  44. if not partial:
  45. return stop_completion(uzbl)
  46. if uzbl.completion.level < LIST:
  47. return
  48. hints = filter(lambda h: h.startswith(partial), uzbl.completion)
  49. if not hints:
  50. del uzbl.config['completion_list']
  51. return
  52. j = len(partial)
  53. l = [ITEM_FORMAT % (escape(h[:j]), h[j:]) for h in sorted(hints)]
  54. uzbl.config['completion_list'] = LIST_FORMAT % ' '.join(l)
  55. def start_completion(uzbl, *args):
  56. comp = uzbl.completion
  57. if comp.locked:
  58. return
  59. (partial, set_completion) = get_incomplete_keyword(uzbl)
  60. if not partial:
  61. return stop_completion(uzbl)
  62. if comp.level < COMPLETE:
  63. comp.level += 1
  64. hints = filter(lambda h: h.startswith(partial), comp)
  65. if not hints:
  66. return
  67. elif len(hints) == 1:
  68. comp.lock()
  69. complete_completion(uzbl, partial, hints[0], set_completion)
  70. comp.unlock()
  71. return
  72. elif partial in hints and comp.level == COMPLETE:
  73. comp.lock()
  74. complete_completion(uzbl, partial, partial, set_completion)
  75. comp.unlock()
  76. return
  77. smalllen, smallest = sorted([(len(h), h) for h in hints])[0]
  78. common = ''
  79. for i in range(len(partial), smalllen):
  80. char, same = smallest[i], True
  81. for hint in hints:
  82. if hint[i] != char:
  83. same = False
  84. break
  85. if not same:
  86. break
  87. common += char
  88. if common:
  89. comp.lock()
  90. partial_completion(uzbl, partial, partial+common)
  91. comp.unlock()
  92. update_completion_list(uzbl)
  93. def add_builtins(uzbl, builtins):
  94. '''Pump the space delimited list of builtin commands into the
  95. builtin list.'''
  96. uzbl.completion.update(builtins.split())
  97. def add_config_key(uzbl, key, value):
  98. '''Listen on the CONFIG_CHANGED event and add config keys to the variable
  99. list for @var<Tab> like expansion support.'''
  100. uzbl.completion.add("@%s" % key)
  101. class Completions(set):
  102. def __init__(self):
  103. set.__init__(self)
  104. self.locked = False
  105. self.level = NONE
  106. def lock(self):
  107. self.locked = True
  108. def unlock(self):
  109. self.locked = False
  110. def init(uzbl):
  111. '''Export functions and connect handlers to events.'''
  112. export_dict(uzbl, {
  113. 'completion': Completions(),
  114. 'start_completion': start_completion,
  115. })
  116. connect_dict(uzbl, {
  117. 'BUILTINS': add_builtins,
  118. 'CONFIG_CHANGED': add_config_key,
  119. 'KEYCMD_CLEARED': stop_completion,
  120. 'KEYCMD_EXEC': stop_completion,
  121. 'KEYCMD_UPDATE': update_completion_list,
  122. 'START_COMPLETION': start_completion,
  123. 'STOP_COMPLETION': stop_completion,
  124. })
  125. uzbl.send('dump_config_as_events')