We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Our readline implementation is broken
The current readline implementation (which replaces `raw_input()`) is broken.  I'm not sure how it has been working before.

The implementation shows a lot of signs of being POC code and should probably be rewritten along with `pwnlib/term/term.py` at some point.  But the current issue should be fixed right away.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwnlib/term/readline.py`
Content:
```
1 import sys
2 from . import term, text, key
3 from . import keymap as km
4 from . import keyconsts as kc
5 cursor = text.reverse
6 
7 buffer_left, buffer_right = u'', u''
8 saved_buffer = None
9 history = []
10 history_idx = None
11 prompt_handle = None
12 buffer_handle = None
13 suggest_handle = None
14 search_idx = None
15 search_results = []
16 startup_hook = None
17 shutdown_hook = None
18 
19 delims = ' /;:.\\'
20 
21 show_completion = True
22 show_suggestions = False
23 
24 complete_hook = None
25 suggest_hook = None
26 
27 tabs = 0
28 
29 def set_completer(completer):
30     global complete_hook, suggest_hook
31     if completer is None:
32         complete_hook = None
33         suggest_hook = None
34     else:
35         complete_hook = completer.complete
36         suggest_hook = completer.suggest
37 
38 def fmt_suggestions(suggestions):
39     if suggestions:
40         s = ''
41         l = max(map(len, suggestions))
42         columns = term.width // (l + 1)
43         column_width = term.width // columns
44         fmt = '%%-%ds' % column_width
45         for j in range(0, len(suggestions), columns):
46             for k in range(columns):
47                 l = j + k
48                 if l < len(suggestions):
49                     s += fmt % suggestions[l]
50             s += '\n'
51     else:
52         s = '\n'
53     return s
54 
55 def auto_complete(*_):
56     global show_suggestions, tabs
57     if search_idx is not None:
58         commit_search()
59         tabs = 0
60     elif tabs == 1:
61         if complete_hook:
62             ret = complete_hook(buffer_left, buffer_right)
63             if ret:
64                 tabs = 0
65                 insert_text(ret)
66     else:
67         show_suggestions = not show_suggestions
68         redisplay()
69 
70 def handle_keypress(trace):
71     global tabs
72     k = trace[-1]
73     if k == '<tab>':
74         tabs += 1
75     else:
76         tabs = 0
77 
78 def clear():
79     global buffer_left, buffer_right, history_idx, search_idx
80     buffer_left, buffer_right = u'', u''
81     history_idx = None
82     search_idx = None
83     redisplay()
84 
85 def redisplay():
86     if buffer_handle:
87         if show_suggestions and suggest_hook:
88             suggestions = suggest_hook(buffer_left, buffer_right)
89             if suggest_handle is None:
90                 h = prompt_handle or buffer_handle
91                 suggest_handle = term.output(before = h)
92             s = fmt_suggestions(suggestions)
93             suggest_handle.update(s)
94         elif suggest_handle:
95             suggest_handle.update('')
96         if search_idx is None:
97             s = None
98             if buffer_right:
99                 s = buffer_left + cursor(buffer_right[0]) + buffer_right[1:]
100             elif show_completion and complete_hook:
101                 ret = complete_hook(buffer_left, buffer_right)
102                 if ret:
103                     s = buffer_left + \
104                       text.underline(cursor(ret[0])) + \
105                       text.underline(ret[1:])
106             s = s or buffer_left + cursor(' ')
107             buffer_handle.update(s)
108         else:
109             if search_results != []:
110                 idx, i, j = search_results[search_idx]
111                 buf = history[idx]
112                 a, b, c = buf[:i], buf[i:j], buf[j:]
113                 s = a + text.bold_green(b) + c
114             else:
115                 s = text.white_on_red(buffer_left)
116             buffer_handle.update('(search) ' + s)
117 
118 def self_insert(trace):
119     if len(trace) != 1:
120         return
121     k = trace[0]
122     if k.type == kc.TYPE_UNICODE and k.mods == kc.MOD_NONE:
123         insert_text(k.code)
124 
125 def set_buffer(left, right):
126     global buffer_left, buffer_right
127     buffer_left = unicode(left)
128     buffer_right = unicode(right)
129     redisplay()
130 
131 def cancel_search(*_):
132     global search_idx
133     if search_idx is not None:
134         search_idx = None
135         redisplay()
136 
137 def commit_search():
138     global search_idx
139     if search_idx is not None:
140         set_buffer(history[search_results[search_idx][0]], u'')
141         search_idx = None
142         redisplay()
143 
144 def update_search_results():
145     global search_results, search_idx, show_suggestions
146     if search_idx is None:
147         return
148     show_suggestions = False
149     if search_results:
150         hidx = search_results[search_idx][0]
151     else:
152         hidx = None
153     search_results = []
154     search_idx = 0
155     if not buffer_left:
156         return
157     for idx, h in enumerate(history):
158         for i in range(0, len(h) - len(buffer_left) + 1):
159             if h[i:i + len(buffer_left)] == buffer_left:
160                 if hidx is not None and idx == hidx:
161                     search_idx = len(search_results)
162                 search_results.append((idx, i, i + len(buffer_left)))
163                 break
164 
165 def search_history(*_):
166     global buffer_left, buffer_right, history_idx, search_idx
167     if search_idx is None:
168         buffer_left, buffer_right = buffer_left + buffer_right, u''
169         history_idx = None
170         search_idx = 0
171         update_search_results()
172     elif search_results:
173         search_idx = (search_idx + 1) % len(search_results)
174     redisplay()
175 
176 def history_prev(*_):
177     global history_idx, saved_buffer
178     if history == []:
179         return
180     cancel_search()
181     if history_idx is None:
182         saved_buffer = (buffer_left, buffer_right)
183         history_idx = -1
184     if history_idx < len(history) - 1:
185         history_idx += 1
186         set_buffer(history[history_idx], u'')
187 
188 def history_next(*_):
189     global history_idx, saved_buffer
190     if history_idx is None:
191         return
192     cancel_search()
193     if history_idx == 0:
194         set_buffer(*saved_buffer)
195         history_idx = None
196         saved_buffer = None
197     else:
198         history_idx -= 1
199         set_buffer(history[history_idx], u'')
200 
201 def backward_char(*_):
202     global buffer_left, buffer_right
203     commit_search()
204     if buffer_left:
205         buffer_right = buffer_left[-1] + buffer_right
206         buffer_left = buffer_left[:-1]
207     redisplay()
208 
209 def forward_char(*_):
210     global buffer_left, buffer_right
211     commit_search()
212     if buffer_right:
213         buffer_left += buffer_right[0]
214         buffer_right = buffer_right[1:]
215     redisplay()
216 
217 def insert_text(s):
218     global history_idx, saved_buffer, buffer_left
219     if history_idx is not None:
220         history_idx = None
221         saved_buffer = None
222     buffer_left += s
223     update_search_results()
224     redisplay()
225 
226 def submit(*_):
227     if search_idx is not None:
228         commit_search()
229     else:
230         keymap.stop()
231 
232 def control_c(*_):
233     global history_idx, saved_buffer
234     if search_idx is not None:
235         cancel_search()
236     elif history_idx is not None:
237         set_buffer(*saved_buffer)
238         history_idx = None
239         saved_buffer = None
240     elif buffer_left or buffer_right:
241         clear()
242     else:
243         raise KeyboardInterrupt
244 
245 def control_d(*_):
246     if buffer_left or buffer_right:
247         return
248     global eof
249     eof = True
250     keymap.stop()
251 
252 def kill_to_end(*_):
253     global buffer_right
254     commit_search()
255     buffer_right = []
256     redisplay()
257 
258 def delete_char_forward(*_):
259     global buffer_right
260     commit_search()
261     if buffer_right:
262         buffer_right = buffer_right[1:]
263         redisplay()
264 
265 def delete_char_backward(*_):
266     global buffer_left
267     if buffer_left:
268         buffer_left = buffer_left[:-1]
269         update_search_results()
270         redisplay()
271 
272 def kill_word_backward(*_):
273     global buffer_left
274     commit_search()
275     flag = False
276     while buffer_left:
277         c = buffer_left[-1]
278         if c[0] in delims:
279             if flag:
280                 break
281         else:
282             flag = True
283         buffer_left = buffer_left[:-1]
284     redisplay()
285 
286 def backward_word(*_):
287     global buffer_left, buffer_right
288     commit_search()
289     flag = False
290     while buffer_left:
291         c = buffer_left[-1]
292         if c[0] in delims:
293             if flag:
294                 break
295         else:
296             flag = True
297         buffer_right = buffer_left[-1] + buffer_right
298         buffer_left = buffer_left[:-1]
299     redisplay()
300 
301 def forward_word(*_):
302     global buffer_left, buffer_right
303     commit_search()
304     flag = False
305     while buffer_right:
306         c = buffer_right[0]
307         if c[0] in delims:
308             if flag:
309                 break
310         else:
311             flag = True
312         buffer_left += buffer_right[0]
313         buffer_right = buffer_right[1:]
314     redisplay()
315 
316 def go_beginning(*_):
317     commit_search()
318     set_buffer(u'', buffer_left + buffer_right)
319 
320 def go_end(*_):
321     commit_search()
322     set_buffer(buffer_left + buffer_right, u'')
323 
324 keymap = km.Keymap({
325     '<nomatch>'   : self_insert,
326     '<up>'        : history_prev,
327     '<down>'      : history_next,
328     '<left>'      : backward_char,
329     '<right>'     : forward_char,
330     '<del>'       : delete_char_backward,
331     '<delete>'    : delete_char_forward,
332     '<enter>'     : submit,
333     'C-<left>'    : backward_word,
334     'C-<right>'   : forward_word,
335     'M-<left>'    : backward_word,
336     'M-<right>'   : forward_word,
337     'C-c'         : control_c,
338     'C-d'         : control_d,
339     'C-k'         : kill_to_end,
340     'C-w'         : kill_word_backward,
341     '<backspace>' : kill_word_backward,
342     'M-<del>'     : kill_word_backward,
343     'C-r'         : search_history,
344     '<escape>'    : cancel_search,
345     'C-a'         : go_beginning,
346     'C-e'         : go_end,
347     '<tab>'       : auto_complete,
348     '<any>'       : handle_keypress,
349     })
350 
351 def readline(_size = None, prompt = '', float = False, priority = 10):
352     # The argument  _size is unused, but is there for compatibility
353     # with the existing readline
354 
355     global buffer_handle, prompt_handle, suggest_handle, eof, \
356         show_suggestions
357 
358     show_suggestions = False
359     eof = False
360     if prompt:
361         prompt_handle = term.output(prompt, float = float, priority = priority)
362     else:
363         prompt_handle = None
364     buffer_handle = term.output(float = float, priority = priority)
365     suggest_handle = None
366     clear()
367     if startup_hook:
368         startup_hook()
369     try:
370         while True:
371             try:
372                 keymap.handle_input()
373                 if eof:
374                     return ''
375                 else:
376                     buffer = buffer_left + buffer_right
377                     if buffer:
378                         history.insert(0, buffer)
379                     return buffer + '\n'
380             except KeyboardInterrupt:
381                 control_c()
382     finally:
383         line = buffer_left + buffer_right + '\n'
384         buffer_handle.update(line)
385         buffer_handle.freeze()
386         buffer_handle = None
387         if prompt_handle:
388             prompt_handle.freeze()
389             prompt_handle = None
390         if suggest_handle:
391             suggest_handle.freeze()
392             suggest_handle = None
393         if shutdown_hook:
394             shutdown_hook()
395 
396 class Wrapper:
397     def __init__(self, fd):
398         self._fd = fd
399     def readline(self, size = None):
400         return readline(size)
401     def __getattr__(self, k):
402         return self._fd.__getattribute__(k)
403 
404 def init():
405     sys.stdin = Wrapper(sys.stdin)
406
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwnlib/term/readline.py b/pwnlib/term/readline.py
--- a/pwnlib/term/readline.py
+++ b/pwnlib/term/readline.py
@@ -83,6 +83,7 @@
     redisplay()
 
 def redisplay():
+    global suggest_handle
     if buffer_handle:
         if show_suggestions and suggest_hook:
             suggestions = suggest_hook(buffer_left, buffer_right)

{"golden_diff": "diff --git a/pwnlib/term/readline.py b/pwnlib/term/readline.py\n--- a/pwnlib/term/readline.py\n+++ b/pwnlib/term/readline.py\n@@ -83,6 +83,7 @@\n     redisplay()\n \n def redisplay():\n+    global suggest_handle\n     if buffer_handle:\n         if show_suggestions and suggest_hook:\n             suggestions = suggest_hook(buffer_left, buffer_right)\n", "issue": "Our readline implementation is broken\nThe current readline implementation (which replaces `raw_input()`) is broken.  I'm not sure how it has been working before.\n\nThe implementation shows a lot of signs of being POC code and should probably be rewritten along with `pwnlib/term/term.py` at some point.  But the current issue should be fixed right away.\n\n", "before_files": [{"content": "import sys\nfrom . import term, text, key\nfrom . import keymap as km\nfrom . import keyconsts as kc\ncursor = text.reverse\n\nbuffer_left, buffer_right = u'', u''\nsaved_buffer = None\nhistory = []\nhistory_idx = None\nprompt_handle = None\nbuffer_handle = None\nsuggest_handle = None\nsearch_idx = None\nsearch_results = []\nstartup_hook = None\nshutdown_hook = None\n\ndelims = ' /;:.\\\\'\n\nshow_completion = True\nshow_suggestions = False\n\ncomplete_hook = None\nsuggest_hook = None\n\ntabs = 0\n\ndef set_completer(completer):\n    global complete_hook, suggest_hook\n    if completer is None:\n        complete_hook = None\n        suggest_hook = None\n    else:\n        complete_hook = completer.complete\n        suggest_hook = completer.suggest\n\ndef fmt_suggestions(suggestions):\n    if suggestions:\n        s = ''\n        l = max(map(len, suggestions))\n        columns = term.width // (l + 1)\n        column_width = term.width // columns\n        fmt = '%%-%ds' % column_width\n        for j in range(0, len(suggestions), columns):\n            for k in range(columns):\n                l = j + k\n                if l < len(suggestions):\n                    s += fmt % suggestions[l]\n            s += '\\n'\n    else:\n        s = '\\n'\n    return s\n\ndef auto_complete(*_):\n    global show_suggestions, tabs\n    if search_idx is not None:\n        commit_search()\n        tabs = 0\n    elif tabs == 1:\n        if complete_hook:\n            ret = complete_hook(buffer_left, buffer_right)\n            if ret:\n                tabs = 0\n                insert_text(ret)\n    else:\n        show_suggestions = not show_suggestions\n        redisplay()\n\ndef handle_keypress(trace):\n    global tabs\n    k = trace[-1]\n    if k == '<tab>':\n        tabs += 1\n    else:\n        tabs = 0\n\ndef clear():\n    global buffer_left, buffer_right, history_idx, search_idx\n    buffer_left, buffer_right = u'', u''\n    history_idx = None\n    search_idx = None\n    redisplay()\n\ndef redisplay():\n    if buffer_handle:\n        if show_suggestions and suggest_hook:\n            suggestions = suggest_hook(buffer_left, buffer_right)\n            if suggest_handle is None:\n                h = prompt_handle or buffer_handle\n                suggest_handle = term.output(before = h)\n            s = fmt_suggestions(suggestions)\n            suggest_handle.update(s)\n        elif suggest_handle:\n            suggest_handle.update('')\n        if search_idx is None:\n            s = None\n            if buffer_right:\n                s = buffer_left + cursor(buffer_right[0]) + buffer_right[1:]\n            elif show_completion and complete_hook:\n                ret = complete_hook(buffer_left, buffer_right)\n                if ret:\n                    s = buffer_left + \\\n                      text.underline(cursor(ret[0])) + \\\n                      text.underline(ret[1:])\n            s = s or buffer_left + cursor(' ')\n            buffer_handle.update(s)\n        else:\n            if search_results != []:\n                idx, i, j = search_results[search_idx]\n                buf = history[idx]\n                a, b, c = buf[:i], buf[i:j], buf[j:]\n                s = a + text.bold_green(b) + c\n            else:\n                s = text.white_on_red(buffer_left)\n            buffer_handle.update('(search) ' + s)\n\ndef self_insert(trace):\n    if len(trace) != 1:\n        return\n    k = trace[0]\n    if k.type == kc.TYPE_UNICODE and k.mods == kc.MOD_NONE:\n        insert_text(k.code)\n\ndef set_buffer(left, right):\n    global buffer_left, buffer_right\n    buffer_left = unicode(left)\n    buffer_right = unicode(right)\n    redisplay()\n\ndef cancel_search(*_):\n    global search_idx\n    if search_idx is not None:\n        search_idx = None\n        redisplay()\n\ndef commit_search():\n    global search_idx\n    if search_idx is not None:\n        set_buffer(history[search_results[search_idx][0]], u'')\n        search_idx = None\n        redisplay()\n\ndef update_search_results():\n    global search_results, search_idx, show_suggestions\n    if search_idx is None:\n        return\n    show_suggestions = False\n    if search_results:\n        hidx = search_results[search_idx][0]\n    else:\n        hidx = None\n    search_results = []\n    search_idx = 0\n    if not buffer_left:\n        return\n    for idx, h in enumerate(history):\n        for i in range(0, len(h) - len(buffer_left) + 1):\n            if h[i:i + len(buffer_left)] == buffer_left:\n                if hidx is not None and idx == hidx:\n                    search_idx = len(search_results)\n                search_results.append((idx, i, i + len(buffer_left)))\n                break\n\ndef search_history(*_):\n    global buffer_left, buffer_right, history_idx, search_idx\n    if search_idx is None:\n        buffer_left, buffer_right = buffer_left + buffer_right, u''\n        history_idx = None\n        search_idx = 0\n        update_search_results()\n    elif search_results:\n        search_idx = (search_idx + 1) % len(search_results)\n    redisplay()\n\ndef history_prev(*_):\n    global history_idx, saved_buffer\n    if history == []:\n        return\n    cancel_search()\n    if history_idx is None:\n        saved_buffer = (buffer_left, buffer_right)\n        history_idx = -1\n    if history_idx < len(history) - 1:\n        history_idx += 1\n        set_buffer(history[history_idx], u'')\n\ndef history_next(*_):\n    global history_idx, saved_buffer\n    if history_idx is None:\n        return\n    cancel_search()\n    if history_idx == 0:\n        set_buffer(*saved_buffer)\n        history_idx = None\n        saved_buffer = None\n    else:\n        history_idx -= 1\n        set_buffer(history[history_idx], u'')\n\ndef backward_char(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    if buffer_left:\n        buffer_right = buffer_left[-1] + buffer_right\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef forward_char(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    if buffer_right:\n        buffer_left += buffer_right[0]\n        buffer_right = buffer_right[1:]\n    redisplay()\n\ndef insert_text(s):\n    global history_idx, saved_buffer, buffer_left\n    if history_idx is not None:\n        history_idx = None\n        saved_buffer = None\n    buffer_left += s\n    update_search_results()\n    redisplay()\n\ndef submit(*_):\n    if search_idx is not None:\n        commit_search()\n    else:\n        keymap.stop()\n\ndef control_c(*_):\n    global history_idx, saved_buffer\n    if search_idx is not None:\n        cancel_search()\n    elif history_idx is not None:\n        set_buffer(*saved_buffer)\n        history_idx = None\n        saved_buffer = None\n    elif buffer_left or buffer_right:\n        clear()\n    else:\n        raise KeyboardInterrupt\n\ndef control_d(*_):\n    if buffer_left or buffer_right:\n        return\n    global eof\n    eof = True\n    keymap.stop()\n\ndef kill_to_end(*_):\n    global buffer_right\n    commit_search()\n    buffer_right = []\n    redisplay()\n\ndef delete_char_forward(*_):\n    global buffer_right\n    commit_search()\n    if buffer_right:\n        buffer_right = buffer_right[1:]\n        redisplay()\n\ndef delete_char_backward(*_):\n    global buffer_left\n    if buffer_left:\n        buffer_left = buffer_left[:-1]\n        update_search_results()\n        redisplay()\n\ndef kill_word_backward(*_):\n    global buffer_left\n    commit_search()\n    flag = False\n    while buffer_left:\n        c = buffer_left[-1]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef backward_word(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    flag = False\n    while buffer_left:\n        c = buffer_left[-1]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_right = buffer_left[-1] + buffer_right\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef forward_word(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    flag = False\n    while buffer_right:\n        c = buffer_right[0]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_left += buffer_right[0]\n        buffer_right = buffer_right[1:]\n    redisplay()\n\ndef go_beginning(*_):\n    commit_search()\n    set_buffer(u'', buffer_left + buffer_right)\n\ndef go_end(*_):\n    commit_search()\n    set_buffer(buffer_left + buffer_right, u'')\n\nkeymap = km.Keymap({\n    '<nomatch>'   : self_insert,\n    '<up>'        : history_prev,\n    '<down>'      : history_next,\n    '<left>'      : backward_char,\n    '<right>'     : forward_char,\n    '<del>'       : delete_char_backward,\n    '<delete>'    : delete_char_forward,\n    '<enter>'     : submit,\n    'C-<left>'    : backward_word,\n    'C-<right>'   : forward_word,\n    'M-<left>'    : backward_word,\n    'M-<right>'   : forward_word,\n    'C-c'         : control_c,\n    'C-d'         : control_d,\n    'C-k'         : kill_to_end,\n    'C-w'         : kill_word_backward,\n    '<backspace>' : kill_word_backward,\n    'M-<del>'     : kill_word_backward,\n    'C-r'         : search_history,\n    '<escape>'    : cancel_search,\n    'C-a'         : go_beginning,\n    'C-e'         : go_end,\n    '<tab>'       : auto_complete,\n    '<any>'       : handle_keypress,\n    })\n\ndef readline(_size = None, prompt = '', float = False, priority = 10):\n    # The argument  _size is unused, but is there for compatibility\n    # with the existing readline\n\n    global buffer_handle, prompt_handle, suggest_handle, eof, \\\n        show_suggestions\n\n    show_suggestions = False\n    eof = False\n    if prompt:\n        prompt_handle = term.output(prompt, float = float, priority = priority)\n    else:\n        prompt_handle = None\n    buffer_handle = term.output(float = float, priority = priority)\n    suggest_handle = None\n    clear()\n    if startup_hook:\n        startup_hook()\n    try:\n        while True:\n            try:\n                keymap.handle_input()\n                if eof:\n                    return ''\n                else:\n                    buffer = buffer_left + buffer_right\n                    if buffer:\n                        history.insert(0, buffer)\n                    return buffer + '\\n'\n            except KeyboardInterrupt:\n                control_c()\n    finally:\n        line = buffer_left + buffer_right + '\\n'\n        buffer_handle.update(line)\n        buffer_handle.freeze()\n        buffer_handle = None\n        if prompt_handle:\n            prompt_handle.freeze()\n            prompt_handle = None\n        if suggest_handle:\n            suggest_handle.freeze()\n            suggest_handle = None\n        if shutdown_hook:\n            shutdown_hook()\n\nclass Wrapper:\n    def __init__(self, fd):\n        self._fd = fd\n    def readline(self, size = None):\n        return readline(size)\n    def __getattr__(self, k):\n        return self._fd.__getattribute__(k)\n\ndef init():\n    sys.stdin = Wrapper(sys.stdin)\n", "path": "pwnlib/term/readline.py"}], "after_files": [{"content": "import sys\nfrom . import term, text, key\nfrom . import keymap as km\nfrom . import keyconsts as kc\ncursor = text.reverse\n\nbuffer_left, buffer_right = u'', u''\nsaved_buffer = None\nhistory = []\nhistory_idx = None\nprompt_handle = None\nbuffer_handle = None\nsuggest_handle = None\nsearch_idx = None\nsearch_results = []\nstartup_hook = None\nshutdown_hook = None\n\ndelims = ' /;:.\\\\'\n\nshow_completion = True\nshow_suggestions = False\n\ncomplete_hook = None\nsuggest_hook = None\n\ntabs = 0\n\ndef set_completer(completer):\n    global complete_hook, suggest_hook\n    if completer is None:\n        complete_hook = None\n        suggest_hook = None\n    else:\n        complete_hook = completer.complete\n        suggest_hook = completer.suggest\n\ndef fmt_suggestions(suggestions):\n    if suggestions:\n        s = ''\n        l = max(map(len, suggestions))\n        columns = term.width // (l + 1)\n        column_width = term.width // columns\n        fmt = '%%-%ds' % column_width\n        for j in range(0, len(suggestions), columns):\n            for k in range(columns):\n                l = j + k\n                if l < len(suggestions):\n                    s += fmt % suggestions[l]\n            s += '\\n'\n    else:\n        s = '\\n'\n    return s\n\ndef auto_complete(*_):\n    global show_suggestions, tabs\n    if search_idx is not None:\n        commit_search()\n        tabs = 0\n    elif tabs == 1:\n        if complete_hook:\n            ret = complete_hook(buffer_left, buffer_right)\n            if ret:\n                tabs = 0\n                insert_text(ret)\n    else:\n        show_suggestions = not show_suggestions\n        redisplay()\n\ndef handle_keypress(trace):\n    global tabs\n    k = trace[-1]\n    if k == '<tab>':\n        tabs += 1\n    else:\n        tabs = 0\n\ndef clear():\n    global buffer_left, buffer_right, history_idx, search_idx\n    buffer_left, buffer_right = u'', u''\n    history_idx = None\n    search_idx = None\n    redisplay()\n\ndef redisplay():\n    global suggest_handle\n    if buffer_handle:\n        if show_suggestions and suggest_hook:\n            suggestions = suggest_hook(buffer_left, buffer_right)\n            if suggest_handle is None:\n                h = prompt_handle or buffer_handle\n                suggest_handle = term.output(before = h)\n            s = fmt_suggestions(suggestions)\n            suggest_handle.update(s)\n        elif suggest_handle:\n            suggest_handle.update('')\n        if search_idx is None:\n            s = None\n            if buffer_right:\n                s = buffer_left + cursor(buffer_right[0]) + buffer_right[1:]\n            elif show_completion and complete_hook:\n                ret = complete_hook(buffer_left, buffer_right)\n                if ret:\n                    s = buffer_left + \\\n                      text.underline(cursor(ret[0])) + \\\n                      text.underline(ret[1:])\n            s = s or buffer_left + cursor(' ')\n            buffer_handle.update(s)\n        else:\n            if search_results != []:\n                idx, i, j = search_results[search_idx]\n                buf = history[idx]\n                a, b, c = buf[:i], buf[i:j], buf[j:]\n                s = a + text.bold_green(b) + c\n            else:\n                s = text.white_on_red(buffer_left)\n            buffer_handle.update('(search) ' + s)\n\ndef self_insert(trace):\n    if len(trace) != 1:\n        return\n    k = trace[0]\n    if k.type == kc.TYPE_UNICODE and k.mods == kc.MOD_NONE:\n        insert_text(k.code)\n\ndef set_buffer(left, right):\n    global buffer_left, buffer_right\n    buffer_left = unicode(left)\n    buffer_right = unicode(right)\n    redisplay()\n\ndef cancel_search(*_):\n    global search_idx\n    if search_idx is not None:\n        search_idx = None\n        redisplay()\n\ndef commit_search():\n    global search_idx\n    if search_idx is not None:\n        set_buffer(history[search_results[search_idx][0]], u'')\n        search_idx = None\n        redisplay()\n\ndef update_search_results():\n    global search_results, search_idx, show_suggestions\n    if search_idx is None:\n        return\n    show_suggestions = False\n    if search_results:\n        hidx = search_results[search_idx][0]\n    else:\n        hidx = None\n    search_results = []\n    search_idx = 0\n    if not buffer_left:\n        return\n    for idx, h in enumerate(history):\n        for i in range(0, len(h) - len(buffer_left) + 1):\n            if h[i:i + len(buffer_left)] == buffer_left:\n                if hidx is not None and idx == hidx:\n                    search_idx = len(search_results)\n                search_results.append((idx, i, i + len(buffer_left)))\n                break\n\ndef search_history(*_):\n    global buffer_left, buffer_right, history_idx, search_idx\n    if search_idx is None:\n        buffer_left, buffer_right = buffer_left + buffer_right, u''\n        history_idx = None\n        search_idx = 0\n        update_search_results()\n    elif search_results:\n        search_idx = (search_idx + 1) % len(search_results)\n    redisplay()\n\ndef history_prev(*_):\n    global history_idx, saved_buffer\n    if history == []:\n        return\n    cancel_search()\n    if history_idx is None:\n        saved_buffer = (buffer_left, buffer_right)\n        history_idx = -1\n    if history_idx < len(history) - 1:\n        history_idx += 1\n        set_buffer(history[history_idx], u'')\n\ndef history_next(*_):\n    global history_idx, saved_buffer\n    if history_idx is None:\n        return\n    cancel_search()\n    if history_idx == 0:\n        set_buffer(*saved_buffer)\n        history_idx = None\n        saved_buffer = None\n    else:\n        history_idx -= 1\n        set_buffer(history[history_idx], u'')\n\ndef backward_char(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    if buffer_left:\n        buffer_right = buffer_left[-1] + buffer_right\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef forward_char(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    if buffer_right:\n        buffer_left += buffer_right[0]\n        buffer_right = buffer_right[1:]\n    redisplay()\n\ndef insert_text(s):\n    global history_idx, saved_buffer, buffer_left\n    if history_idx is not None:\n        history_idx = None\n        saved_buffer = None\n    buffer_left += s\n    update_search_results()\n    redisplay()\n\ndef submit(*_):\n    if search_idx is not None:\n        commit_search()\n    else:\n        keymap.stop()\n\ndef control_c(*_):\n    global history_idx, saved_buffer\n    if search_idx is not None:\n        cancel_search()\n    elif history_idx is not None:\n        set_buffer(*saved_buffer)\n        history_idx = None\n        saved_buffer = None\n    elif buffer_left or buffer_right:\n        clear()\n    else:\n        raise KeyboardInterrupt\n\ndef control_d(*_):\n    if buffer_left or buffer_right:\n        return\n    global eof\n    eof = True\n    keymap.stop()\n\ndef kill_to_end(*_):\n    global buffer_right\n    commit_search()\n    buffer_right = []\n    redisplay()\n\ndef delete_char_forward(*_):\n    global buffer_right\n    commit_search()\n    if buffer_right:\n        buffer_right = buffer_right[1:]\n        redisplay()\n\ndef delete_char_backward(*_):\n    global buffer_left\n    if buffer_left:\n        buffer_left = buffer_left[:-1]\n        update_search_results()\n        redisplay()\n\ndef kill_word_backward(*_):\n    global buffer_left\n    commit_search()\n    flag = False\n    while buffer_left:\n        c = buffer_left[-1]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef backward_word(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    flag = False\n    while buffer_left:\n        c = buffer_left[-1]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_right = buffer_left[-1] + buffer_right\n        buffer_left = buffer_left[:-1]\n    redisplay()\n\ndef forward_word(*_):\n    global buffer_left, buffer_right\n    commit_search()\n    flag = False\n    while buffer_right:\n        c = buffer_right[0]\n        if c[0] in delims:\n            if flag:\n                break\n        else:\n            flag = True\n        buffer_left += buffer_right[0]\n        buffer_right = buffer_right[1:]\n    redisplay()\n\ndef go_beginning(*_):\n    commit_search()\n    set_buffer(u'', buffer_left + buffer_right)\n\ndef go_end(*_):\n    commit_search()\n    set_buffer(buffer_left + buffer_right, u'')\n\nkeymap = km.Keymap({\n    '<nomatch>'   : self_insert,\n    '<up>'        : history_prev,\n    '<down>'      : history_next,\n    '<left>'      : backward_char,\n    '<right>'     : forward_char,\n    '<del>'       : delete_char_backward,\n    '<delete>'    : delete_char_forward,\n    '<enter>'     : submit,\n    'C-<left>'    : backward_word,\n    'C-<right>'   : forward_word,\n    'M-<left>'    : backward_word,\n    'M-<right>'   : forward_word,\n    'C-c'         : control_c,\n    'C-d'         : control_d,\n    'C-k'         : kill_to_end,\n    'C-w'         : kill_word_backward,\n    '<backspace>' : kill_word_backward,\n    'M-<del>'     : kill_word_backward,\n    'C-r'         : search_history,\n    '<escape>'    : cancel_search,\n    'C-a'         : go_beginning,\n    'C-e'         : go_end,\n    '<tab>'       : auto_complete,\n    '<any>'       : handle_keypress,\n    })\n\ndef readline(_size = None, prompt = '', float = False, priority = 10):\n    # The argument  _size is unused, but is there for compatibility\n    # with the existing readline\n\n    global buffer_handle, prompt_handle, suggest_handle, eof, \\\n        show_suggestions\n\n    show_suggestions = False\n    eof = False\n    if prompt:\n        prompt_handle = term.output(prompt, float = float, priority = priority)\n    else:\n        prompt_handle = None\n    buffer_handle = term.output(float = float, priority = priority)\n    suggest_handle = None\n    clear()\n    if startup_hook:\n        startup_hook()\n    try:\n        while True:\n            try:\n                keymap.handle_input()\n                if eof:\n                    return ''\n                else:\n                    buffer = buffer_left + buffer_right\n                    if buffer:\n                        history.insert(0, buffer)\n                    return buffer + '\\n'\n            except KeyboardInterrupt:\n                control_c()\n    finally:\n        line = buffer_left + buffer_right + '\\n'\n        buffer_handle.update(line)\n        buffer_handle.freeze()\n        buffer_handle = None\n        if prompt_handle:\n            prompt_handle.freeze()\n            prompt_handle = None\n        if suggest_handle:\n            suggest_handle.freeze()\n            suggest_handle = None\n        if shutdown_hook:\n            shutdown_hook()\n\nclass Wrapper:\n    def __init__(self, fd):\n        self._fd = fd\n    def readline(self, size = None):\n        return readline(size)\n    def __getattr__(self, k):\n        return self._fd.__getattribute__(k)\n\ndef init():\n    sys.stdin = Wrapper(sys.stdin)\n", "path": "pwnlib/term/readline.py"}]}